From efbd5cab85c589057602c402d53407b6abde3217 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Mon, 18 Sep 2023 15:32:43 -0400 Subject: [PATCH] Convert SignalService, Database, Group, Payment, and other remaining protos to wire. --- app/build.gradle | 21 +- .../securesms/database/GroupTableTest.kt | 44 +- .../database/MessageTableTest_gifts.kt | 24 +- .../RecipientTableTest_getAndPossiblyMerge.kt | 4 +- .../messages/EditMessageSyncProcessorTest.kt | 68 +- ...geContentProcessor__recipientStatusTest.kt | 10 +- .../MessageProcessingPerformanceTest.kt | 7 +- .../securesms/messages/TestMessage.kt | 7 +- .../messages/TimingMessageContentProcessor.kt | 9 +- .../securesms/testing/AliceClient.kt | 2 +- .../securesms/testing/BobClient.kt | 9 +- .../securesms/testing/FakeClientHelpers.kt | 34 +- .../securesms/testing/GroupTestingUtils.kt | 16 +- .../securesms/testing/MessageContentFuzzer.kt | 103 +- .../securesms/testing/TestProtos.kt | 70 - .../absbackup/backupables/SvrAuthTokens.kt | 4 +- .../attachments/PointerAttachment.java | 10 +- .../securesms/audio/AudioFileInfo.java | 14 +- .../securesms/audio/AudioHash.java | 4 +- .../securesms/audio/AudioWaveForms.kt | 2 +- .../thoughtcrime/securesms/badges/Badges.kt | 20 +- .../securesms/badges/gifts/GiftMessageView.kt | 3 +- .../securesms/badges/gifts/Gifts.kt | 2 +- .../received/ViewReceivedGiftBottomSheet.kt | 2 +- .../viewgift/sent/ViewSentGiftBottomSheet.kt | 4 +- .../securesms/calls/log/CallLogRow.kt | 4 +- .../changenumber/ChangeNumberRepository.kt | 30 +- .../internal/InternalSettingsRepository.kt | 2 +- .../ConversationSettingsRepository.kt | 7 +- .../contactshare/ContactModelMapper.java | 72 +- .../conversation/ConversationItem.java | 4 +- .../conversation/ConversationUpdateItem.java | 2 +- .../securesms/conversation/MessageStyler.kt | 12 +- .../conversation/colors/ChatColors.kt | 22 +- .../conversation/drafts/DraftRepository.kt | 2 +- .../conversation/drafts/DraftViewModel.kt | 6 +- .../conversation/v2/ConversationFragment.kt | 2 +- .../securesms/database/BodyRangeUtil.kt | 8 +- .../securesms/database/CallTable.kt | 14 +- .../securesms/database/ChatColorsTable.kt | 6 +- .../securesms/database/GroupTable.kt | 52 +- .../securesms/database/MentionUtil.java | 32 +- .../database/MessageSendLogTables.kt | 10 +- .../securesms/database/MessageTable.kt | 112 +- .../database/PaymentMetaDataUtil.java | 38 +- .../securesms/database/PaymentTable.java | 24 +- .../securesms/database/RecipientTable.kt | 121 +- .../database/SentStorySyncManifest.kt | 10 +- .../migration/V149_LegacyMigrations.kt | 22 +- .../database/model/AvatarPickerDatabase.kt | 22 +- .../database/model/BodyRangeListSerializer.kt | 4 +- .../database/model/DatabaseProtosUtil.kt | 37 +- .../model/GroupCallUpdateDetailsUtil.java | 17 +- .../model/GroupCallUpdateMessageFactory.java | 6 +- .../securesms/database/model/GroupRecord.kt | 8 +- .../model/GroupsV2UpdateMessageProducer.java | 340 ++--- .../database/model/MessageLogEntry.kt | 4 +- .../database/model/MessageRecord.java | 119 +- .../exporter/SignalSmsExportReader.kt | 10 +- .../exporter/SignalSmsExportService.kt | 24 +- .../thoughtcrime/securesms/fonts/TextFont.kt | 1 - .../securesms/glide/GiftBadgeModel.kt | 3 +- .../securesms/groups/GroupId.java | 4 +- .../securesms/groups/GroupManagerV1.java | 18 +- .../securesms/groups/GroupManagerV2.java | 147 +-- .../securesms/groups/GroupProtoUtil.java | 44 +- .../groups/GroupsV1MigrationUtil.java | 4 +- .../securesms/groups/LiveGroup.java | 13 +- .../PendingMemberInvitesRepository.java | 17 +- .../joining/GroupDetails.java | 8 +- .../joining/GroupJoinRepository.java | 2 +- .../groups/v2/GroupInviteLinkUrl.java | 38 +- .../securesms/groups/v2/ProfileKeySet.java | 30 +- .../v2/processing/GlobalGroupState.java | 4 +- .../v2/processing/GroupStateMapper.java | 16 +- .../v2/processing/GroupsV2StateProcessor.java | 124 +- .../v2/processing/LocalGroupLogEntry.java | 2 +- .../v2/processing/ServerGroupLogEntry.java | 6 +- .../PushProcessMessageJobMigration.kt | 36 +- .../PushProcessMessageQueueJobMigration.java | 14 +- .../jobs/AutomaticSessionResetJob.java | 24 +- .../securesms/jobs/CallLinkUpdateSendJob.kt | 9 +- .../securesms/jobs/CallLogEventSendJob.kt | 18 +- .../securesms/jobs/CallSyncEventJob.kt | 4 +- .../jobs/DonationReceiptRedemptionJob.java | 8 +- .../securesms/jobs/GiftSendJob.kt | 4 +- .../jobs/GroupV2UpdateSelfProfileKeyJob.java | 15 +- .../securesms/jobs/IndividualSendJob.java | 7 +- .../jobs/MultiDeviceCallLinkSyncJob.kt | 17 +- .../jobs/MultiDeviceContactSyncJob.kt | 2 +- .../MultiDeviceOutgoingPaymentSyncJob.java | 14 +- .../securesms/jobs/PnpInitializeDevicesJob.kt | 18 +- .../jobs/PushDistributionListSendJob.java | 8 +- .../securesms/jobs/PushGroupSendJob.java | 39 +- .../jobs/PushGroupSilentUpdateSendJob.java | 31 +- .../securesms/jobs/PushProcessMessageJob.kt | 22 +- .../securesms/jobs/PushSendJob.java | 33 +- .../jobs/RefreshCallLinkDetailsJob.kt | 8 +- .../securesms/jobs/ResendMessageJob.java | 22 +- .../jobs/RetrieveRemoteAnnouncementsJob.kt | 2 +- .../securesms/jobs/StorageSyncJob.java | 6 +- .../securesms/keyvalue/ChatColorsValues.kt | 8 +- .../securesms/keyvalue/DonationsValues.kt | 8 +- ...GroupsV2AuthorizationSignalStoreCache.java | 31 +- .../securesms/keyvalue/PaymentsValues.kt | 12 +- .../PendingChangeNumberMetadataSerializer.kt | 4 +- .../securesms/keyvalue/SignalStoreValues.java | 21 +- .../securesms/keyvalue/WallpaperValues.java | 23 +- .../linkpreview/LinkPreviewRepository.java | 6 +- .../mediasend/MediaSendActivityResult.kt | 4 +- .../text/send/TextStoryPostSendRepository.kt | 4 +- .../MessageRequestRepository.java | 4 +- .../messages/CallMessageProcessor.kt | 143 ++- .../messages/DataMessageProcessor.kt | 325 ++--- .../messages/EditMessageProcessor.kt | 52 +- .../messages/IncomingMessageObserver.kt | 30 +- .../messages/MessageContentProcessor.kt | 133 +- .../securesms/messages/MessageDecryptor.kt | 64 +- .../messages/ReceiptMessageProcessor.kt | 44 +- .../messages/SignalServiceProtoUtil.kt | 105 +- .../messages/StoryMessageProcessor.kt | 114 +- .../securesms/messages/StorySendUtil.kt | 16 +- .../messages/SyncMessageProcessor.kt | 491 ++++---- .../ApplyUnknownFieldsToSelfMigrationJob.java | 2 - .../securesms/mms/MessageGroupContext.java | 44 +- .../thoughtcrime/securesms/mms/QuoteModel.kt | 6 +- .../notifications/v2/NotificationItem.kt | 2 +- .../securesms/payments/CryptoValueUtil.java | 19 +- .../payments/MobileCoinLedgerWrapper.java | 34 +- .../MobileCoinPublicAddressProfileUtil.java | 35 +- .../securesms/payments/PaymentParcelable.java | 9 +- .../payments/ReconstructedPayment.java | 2 +- .../securesms/payments/Wallet.java | 45 +- .../reconciliation/LedgerReconcile.java | 17 +- .../profiles/spoofing/ReviewCard.java | 16 +- .../spoofing/ReviewCardViewHolder.java | 4 +- .../profiles/spoofing/ReviewRecipient.java | 4 +- .../profiles/spoofing/ReviewUtil.java | 2 +- .../securesms/recipients/Recipient.java | 9 +- .../ShareableGroupLinkRepository.java | 5 +- .../securesms/search/SearchRepository.java | 13 +- .../webrtc/CallEventSyncMessageUtil.kt | 24 +- .../service/webrtc/SignalCallManager.java | 9 +- .../securesms/service/webrtc/WebRtcData.java | 16 +- .../service/webrtc/links/CallLinkRoomId.kt | 5 +- .../securesms/sharing/MultiShareArgs.java | 8 +- .../securesms/sharing/MultiShareSender.java | 16 +- .../sms/GroupV2UpdateMessageUtil.java | 18 +- .../sms/IncomingGroupUpdateMessage.java | 5 - .../securesms/storage/StorageSyncHelper.java | 2 +- .../securesms/stories/StoryTextPostModel.kt | 16 +- .../securesms/stories/StoryTextPostView.kt | 2 +- .../stories/dialogs/StoryContextMenu.kt | 2 +- .../viewer/page/StoryViewerPageRepository.kt | 4 +- .../stories/viewer/post/StoryPostViewModel.kt | 2 +- .../viewer/post/StoryTextPostRepository.kt | 2 +- .../securesms/util/EarlyMessageCacheEntry.kt | 4 +- .../securesms/util/GroupUtil.java | 23 +- .../securesms/util/IdentityUtil.java | 10 +- .../securesms/util/MessageRecordUtil.kt | 2 +- .../securesms/util/ProfileUtil.java | 18 +- .../wallpaper/ChatWallpaperFactory.java | 28 +- .../wallpaper/GradientChatWallpaper.java | 26 +- .../wallpaper/SingleColorChatWallpaper.java | 12 +- .../securesms/wallpaper/UriChatWallpaper.java | 14 +- .../main/{proto => protowire}/Database.proto | 3 +- .../main/{proto => protowire}/Payments.proto | 4 +- .../securesms/database/GV2Transformer.kt | 16 +- .../database/GV2UpdateTransformer.kt | 2 +- .../database/MessageRangesTransformer.kt | 12 +- .../ProfileKeyCredentialTransformer.kt | 2 +- .../conversation/MessageStylerTest.kt | 44 +- .../securesms/database/BodyRangeUtilTest.kt | 60 +- .../securesms/database/GroupTestUtil.kt | 78 +- .../database/PaymentMetaDataUtilTest.java | 11 +- .../GroupsV2UpdateMessageProducerTest.java | 34 +- ...NewContextWithAppendedDeleteJoinRequest.kt | 25 +- .../groups/GroupManagerV2Test_edit.kt | 4 +- .../securesms/groups/v2/ChangeBuilder.java | 71 +- ...inkUrl_InvalidGroupLinkException_Test.java | 20 +- .../v2/processing/GlobalGroupStateTest.java | 4 +- .../v2/processing/GroupStateMapperTest.java | 314 +++-- .../processing/GroupsV2StateProcessorTest.kt | 51 +- ...obileCoinPublicAddressProfileUtilTest.java | 114 +- .../reconciliation/LedgerReconcileTest.java | 44 +- .../sms/GroupV2UpdateMessageUtilTest.java | 52 +- .../stories/dialogs/StoryContextMenuTest.kt | 6 +- .../databaseprotos/DecryptedGroupHelper.kt | 34 +- build.gradle | 1 + core-util/build.gradle | 21 +- core-util/src/main/java/ProtoUtil.kt | 19 + .../org/signal/core/util/tracing/Tracer.java | 118 +- .../src/main/{proto => protowire}/Trace.proto | 0 gradle/verification-metadata.xml | 13 + libsignal/service/build.gradle | 25 +- libsignal/service/lint.xml | 1 + .../squareup/wire/internal/CountNonDefault.kt | 57 + .../api/SignalServiceAccountManager.java | 6 +- .../api/SignalServiceMessageSender.java | 865 +++++++------ .../signalservice/api/SignalWebSocket.java | 4 +- .../api/crypto/EnvelopeContent.java | 20 +- .../api/crypto/SignalServiceCipher.java | 69 +- .../api/crypto/SignalServiceCipherResult.kt | 4 +- ...ChangeActionsBuilderChangeSetModifier.java | 158 --- ...upChangeActionsBuilderChangeSetModifier.kt | 118 ++ .../groupsv2/DecryptedGroupHistoryEntry.java | 2 +- .../api/groupsv2/DecryptedGroupUtil.java | 415 +++--- ...ChangeActionsBuilderChangeSetModifier.java | 130 -- ...upChangeActionsBuilderChangeSetModifier.kt | 109 ++ .../api/groupsv2/GroupChangeReconstruct.java | 207 +-- .../api/groupsv2/GroupChangeUtil.java | 148 +-- .../api/groupsv2/GroupsV2Api.java | 20 +- .../api/groupsv2/GroupsV2Operations.java | 702 ++++++----- .../api/groupsv2/PartialDecryptedGroup.java | 6 +- .../api/messages/EnvelopeContentValidator.kt | 204 ++- .../api/messages/EnvelopeResponse.kt | 2 +- .../api/messages/SendMessageResult.java | 2 +- .../SignalServiceAttachmentRemoteId.java | 86 +- .../api/messages/SignalServiceDataMessage.kt | 6 +- .../api/messages/SignalServiceGroupV2.java | 17 +- .../messages/SignalServiceStoryMessage.java | 22 +- .../api/messages/calls/HangupMessage.java | 20 +- .../api/messages/calls/OfferMessage.java | 15 +- .../api/messages/calls/OpaqueMessage.java | 8 +- .../DeviceContactsInputStream.java | 47 +- .../DeviceContactsOutputStream.java | 59 +- .../multidevice/DeviceGroupsOutputStream.java | 93 -- .../multidevice/OutgoingPaymentMessage.java | 5 +- .../messages/multidevice/RequestMessage.java | 14 +- .../multidevice/SignalServiceSyncMessage.java | 8 +- .../api/payments/MoneyProtobufUtil.java | 35 - .../signalservice/api/push/ServiceId.kt | 10 +- .../signalservice/api/push/ServiceIds.java | 5 +- .../api/util/AttachmentPointerUtil.java | 88 +- .../signalservice/api/util/UuidUtil.java | 10 +- .../internal/push/PushServiceSocket.java | 37 +- ...ignalServiceAddressProtobufSerializer.java | 33 - ...gnalServiceMetadataProtobufSerializer.java | 44 - .../DecryptedGroups.proto | 0 .../main/{proto => protowire}/Groups.proto | 0 .../InternalSerialization.proto | 0 .../{proto => protowire}/SignalService.proto | 4 +- .../api/groupsv2/DecryptedGroupUtilTest.java | 75 +- .../DecryptedGroupUtil_apply_Test.java | 1122 ++++++++--------- .../DecryptedGroupUtil_empty_Test.java | 141 ++- .../groupsv2/GroupChangeReconstructTest.java | 286 ++--- .../GroupChangeUtil_changeIsEmpty_Test.java | 136 +- .../GroupChangeUtil_resolveConflict_Test.java | 975 +++++++------- ...il_resolveConflict_decryptedOnly_Test.java | 690 +++++----- .../groupsv2/GroupsV2Operations_ban_Test.java | 45 +- ...roupsV2Operations_decrypt_change_Test.java | 352 +++--- ...Operations_decrypt_groupJoinInfo_Test.java | 54 +- ...GroupsV2Operations_decrypt_group_Test.java | 287 +++-- .../api/groupsv2/ProtoTestUtils.java | 153 +-- .../api/groupsv2/ProtobufTestUtils.java | 18 +- .../signalservice/api/util/UuidUtilTest.java | 6 +- ...lServiceAddressProtobufSerializerTest.java | 33 - microbenchmark/build.gradle.kts | 1 - wire-handler/README.md | 11 + wire-handler/gradle | 1 + wire-handler/gradlew | 1 + wire-handler/gradlew.bat | 1 + wire-handler/lib/build.gradle.kts | 17 + .../main/kotlin/org/signal/wire/Factory.kt | 9 + .../main/kotlin/org/signal/wire/Handler.kt | 54 + wire-handler/settings.gradle.kts | 11 + wire-handler/wire-handler-1.0.0.jar | Bin 0 -> 6180 bytes 267 files changed, 7100 insertions(+), 7214 deletions(-) delete mode 100644 app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt rename app/src/main/{proto => protowire}/Database.proto (99%) rename app/src/main/{proto => protowire}/Payments.proto (92%) create mode 100644 core-util/src/main/java/ProtoUtil.kt rename core-util/src/main/{proto => protowire}/Trace.proto (100%) create mode 100644 libsignal/service/src/main/java/com/squareup/wire/internal/CountNonDefault.kt delete mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.java create mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.kt delete mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.java create mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.kt delete mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceGroupsOutputStream.java delete mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/payments/MoneyProtobufUtil.java delete mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializer.java delete mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceMetadataProtobufSerializer.java rename libsignal/service/src/main/{proto => protowire}/DecryptedGroups.proto (100%) rename libsignal/service/src/main/{proto => protowire}/Groups.proto (100%) rename libsignal/service/src/main/{proto => protowire}/InternalSerialization.proto (100%) rename libsignal/service/src/main/{proto => protowire}/SignalService.proto (99%) delete mode 100644 libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java create mode 100644 wire-handler/README.md create mode 120000 wire-handler/gradle create mode 120000 wire-handler/gradlew create mode 120000 wire-handler/gradlew.bat create mode 100644 wire-handler/lib/build.gradle.kts create mode 100644 wire-handler/lib/src/main/kotlin/org/signal/wire/Factory.kt create mode 100644 wire-handler/lib/src/main/kotlin/org/signal/wire/Handler.kt create mode 100644 wire-handler/settings.gradle.kts create mode 100644 wire-handler/wire-handler-1.0.0.jar diff --git a/app/build.gradle b/app/build.gradle index 6171487bbd..9b26aeac9f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,6 @@ import com.android.build.api.dsl.ManagedVirtualDevice plugins { id 'com.android.application' id 'kotlin-android' - id 'com.google.protobuf' id 'androidx.navigation.safeargs' id 'org.jlleitschuh.gradle.ktlint' id 'org.jetbrains.kotlin.android' @@ -16,21 +15,6 @@ plugins { apply from: 'static-ips.gradle' -protobuf { - protoc { - artifact = 'com.google.protobuf:protoc:3.18.0' - } - generateProtoTasks { - all().each { task -> - task.builtins { - java { - option "lite" - } - } - } - } -} - wire { kotlin { javaInterop = true @@ -538,11 +522,8 @@ dependencies { implementation project(':photoview') implementation libs.libsignal.android - implementation libs.google.protobuf.javalite - implementation(libs.mobilecoin) { - exclude group: 'com.google.protobuf' - } + implementation libs.mobilecoin implementation libs.signal.ringrtc diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt index 42641c87bd..2657332a86 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/GroupTableTest.kt @@ -293,22 +293,22 @@ class GroupTableTest { private fun insertPushGroup( members: List = listOf( - DecryptedMember.newBuilder() - .setAciBytes(harness.self.requireAci().toByteString()) - .setJoinedAtRevision(0) - .setRole(Member.Role.DEFAULT) + DecryptedMember.Builder() + .aciBytes(harness.self.requireAci().toByteString()) + .joinedAtRevision(0) + .role(Member.Role.DEFAULT) .build(), - DecryptedMember.newBuilder() - .setAciBytes(Recipient.resolved(harness.others[0]).requireAci().toByteString()) - .setJoinedAtRevision(0) - .setRole(Member.Role.DEFAULT) + DecryptedMember.Builder() + .aciBytes(Recipient.resolved(harness.others[0]).requireAci().toByteString()) + .joinedAtRevision(0) + .role(Member.Role.DEFAULT) .build() ) ): GroupId { val groupMasterKey = GroupMasterKey(Random.nextBytes(GroupMasterKey.SIZE)) - val decryptedGroupState = DecryptedGroup.newBuilder() - .addAllMembers(members) - .setRevision(0) + val decryptedGroupState = DecryptedGroup.Builder() + .members(members) + .revision(0) .build() return groupTable.create(groupMasterKey, decryptedGroupState)!! @@ -317,23 +317,23 @@ class GroupTableTest { private fun insertPushGroupWithSelfAndOthers(others: List): GroupId { val groupMasterKey = GroupMasterKey(Random.nextBytes(GroupMasterKey.SIZE)) - val selfMember: DecryptedMember = DecryptedMember.newBuilder() - .setAciBytes(harness.self.requireAci().toByteString()) - .setJoinedAtRevision(0) - .setRole(Member.Role.DEFAULT) + val selfMember: DecryptedMember = DecryptedMember.Builder() + .aciBytes(harness.self.requireAci().toByteString()) + .joinedAtRevision(0) + .role(Member.Role.DEFAULT) .build() val otherMembers: List = others.map { id -> - DecryptedMember.newBuilder() - .setAciBytes(Recipient.resolved(id).requireAci().toByteString()) - .setJoinedAtRevision(0) - .setRole(Member.Role.DEFAULT) + DecryptedMember.Builder() + .aciBytes(Recipient.resolved(id).requireAci().toByteString()) + .joinedAtRevision(0) + .role(Member.Role.DEFAULT) .build() } - val decryptedGroupState = DecryptedGroup.newBuilder() - .addAllMembers(listOf(selfMember) + otherMembers) - .setRevision(0) + val decryptedGroupState = DecryptedGroup.Builder() + .members(listOf(selfMember) + otherMembers) + .revision(0) .build() return groupTable.create(groupMasterKey, decryptedGroupState)!! diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt index 12a7cede4f..3fe7d7ed5c 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt @@ -48,7 +48,7 @@ class MessageTableTest_gifts { val messageId = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 1, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val result = mms.setOutgoingGiftsRevealed(listOf(messageId)) @@ -62,7 +62,7 @@ class MessageTableTest_gifts { val messageId = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 1, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) mms.setOutgoingGiftsRevealed(listOf(messageId)) @@ -76,13 +76,13 @@ class MessageTableTest_gifts { val messageId = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 1, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 2, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val result = mms.setOutgoingGiftsRevealed(listOf(messageId)) @@ -96,13 +96,13 @@ class MessageTableTest_gifts { val messageId = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 1, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val messageId2 = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 2, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val result = mms.setOutgoingGiftsRevealed(listOf(messageId, messageId2)) @@ -115,13 +115,13 @@ class MessageTableTest_gifts { val messageId = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 1, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val messageId2 = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 2, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) MmsHelper.insert( @@ -140,13 +140,13 @@ class MessageTableTest_gifts { val messageId = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 1, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val messageId2 = MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 2, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val messageId3 = MmsHelper.insert( @@ -165,13 +165,13 @@ class MessageTableTest_gifts { MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 1, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) MmsHelper.insert( recipient = Recipient.resolved(recipients[0]), sentTimeMillis = 2, - giftBadge = GiftBadge.getDefaultInstance() + giftBadge = GiftBadge() ) val messageId3 = MmsHelper.insert( diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt index a3afff91cd..ea48c05782 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt @@ -1228,7 +1228,7 @@ class RecipientTableTest_getAndPossiblyMerge { .use { cursor: Cursor -> if (cursor.moveToFirst()) { val bytes = Base64.decode(cursor.requireNonNullString(MessageTable.BODY)) - ThreadMergeEvent.parseFrom(bytes) + ThreadMergeEvent.ADAPTER.decode(bytes) } else { null } @@ -1246,7 +1246,7 @@ class RecipientTableTest_getAndPossiblyMerge { .use { cursor: Cursor -> if (cursor.moveToFirst()) { val bytes = Base64.decode(cursor.requireNonNullString(MessageTable.BODY)) - SessionSwitchoverEvent.parseFrom(bytes) + SessionSwitchoverEvent.ADAPTER.decode(bytes) } else { null } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/EditMessageSyncProcessorTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/EditMessageSyncProcessorTest.kt index fcccdf8a0c..82bb5ccc70 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/EditMessageSyncProcessorTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/EditMessageSyncProcessorTest.kt @@ -22,8 +22,9 @@ import org.thoughtcrime.securesms.testing.MessageContentFuzzer import org.thoughtcrime.securesms.testing.SignalActivityRule import org.thoughtcrime.securesms.testing.assertIs import org.thoughtcrime.securesms.util.MessageTableTestUtils -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.EditMessage +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.EditMessage +import org.whispersystems.signalservice.internal.push.SyncMessage import kotlin.time.Duration.Companion.seconds @RunWith(AndroidJUnit4::class) @@ -67,16 +68,17 @@ class EditMessageSyncProcessorTest { val content = MessageContentFuzzer.fuzzTextMessage() val metadata = MessageContentFuzzer.envelopeMetadata(harness.self.id, toRecipient.id) - val syncContent = SignalServiceProtos.Content.newBuilder().setSyncMessage( - SignalServiceProtos.SyncMessage.newBuilder().setSent( - SignalServiceProtos.SyncMessage.Sent.newBuilder() - .setDestinationServiceId(metadata.destinationServiceId.toString()) - .setTimestamp(originalTimestamp) - .setExpirationStartTimestamp(originalTimestamp) - .setMessage(content.dataMessage) - ) + val syncContent = Content.Builder().syncMessage( + SyncMessage.Builder().sent( + SyncMessage.Sent.Builder() + .destinationServiceId(metadata.destinationServiceId.toString()) + .timestamp(originalTimestamp) + .expirationStartTimestamp(originalTimestamp) + .message(content.dataMessage) + .build() + ).build() ).build() - SignalDatabase.recipients.setExpireMessages(toRecipient.id, content.dataMessage.expireTimer) + SignalDatabase.recipients.setExpireMessages(toRecipient.id, content.dataMessage?.expireTimer ?: 0) val syncTextMessage = TestMessage( envelope = MessageContentFuzzer.envelope(originalTimestamp), content = syncContent, @@ -86,18 +88,20 @@ class EditMessageSyncProcessorTest { val editTimestamp = originalTimestamp + 200 val editedContent = MessageContentFuzzer.fuzzTextMessage() - val editSyncContent = SignalServiceProtos.Content.newBuilder().setSyncMessage( - SignalServiceProtos.SyncMessage.newBuilder().setSent( - SignalServiceProtos.SyncMessage.Sent.newBuilder() - .setDestinationServiceId(metadata.destinationServiceId.toString()) - .setTimestamp(editTimestamp) - .setExpirationStartTimestamp(editTimestamp) - .setEditMessage( - EditMessage.newBuilder() - .setDataMessage(editedContent.dataMessage) - .setTargetSentTimestamp(originalTimestamp) + val editSyncContent = Content.Builder().syncMessage( + SyncMessage.Builder().sent( + SyncMessage.Sent.Builder() + .destinationServiceId(metadata.destinationServiceId.toString()) + .timestamp(editTimestamp) + .expirationStartTimestamp(editTimestamp) + .editMessage( + EditMessage.Builder() + .dataMessage(editedContent.dataMessage) + .targetSentTimestamp(originalTimestamp) + .build() ) - ) + .build() + ).build() ).build() val syncEditMessage = TestMessage( @@ -109,38 +113,38 @@ class EditMessageSyncProcessorTest { testResult.runSync(listOf(syncTextMessage, syncEditMessage)) - SignalDatabase.recipients.setExpireMessages(toRecipient.id, content.dataMessage.expireTimer / 1000) + SignalDatabase.recipients.setExpireMessages(toRecipient.id, (content.dataMessage?.expireTimer ?: 0) / 1000) val originalTextMessage = OutgoingMessage( threadRecipient = toRecipient, sentTimeMillis = originalTimestamp, - body = content.dataMessage.body, - expiresIn = content.dataMessage.expireTimer.seconds.inWholeMilliseconds, + body = content.dataMessage?.body ?: "", + expiresIn = content.dataMessage?.expireTimer?.seconds?.inWholeMilliseconds ?: 0, isUrgent = true, isSecure = true, - bodyRanges = content.dataMessage.bodyRangesList.toBodyRangeList() + bodyRanges = content.dataMessage?.bodyRanges.toBodyRangeList() ) val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(toRecipient) val originalMessageId = SignalDatabase.messages.insertMessageOutbox(originalTextMessage, threadId, false, null) SignalDatabase.messages.markAsSent(originalMessageId, true) - if (content.dataMessage.expireTimer > 0) { + if ((content.dataMessage?.expireTimer ?: 0) > 0) { SignalDatabase.messages.markExpireStarted(originalMessageId, originalTimestamp) } val editMessage = OutgoingMessage( threadRecipient = toRecipient, sentTimeMillis = editTimestamp, - body = editedContent.dataMessage.body, - expiresIn = content.dataMessage.expireTimer.seconds.inWholeMilliseconds, + body = editedContent.dataMessage?.body ?: "", + expiresIn = content.dataMessage?.expireTimer?.seconds?.inWholeMilliseconds ?: 0, isUrgent = true, isSecure = true, - bodyRanges = editedContent.dataMessage.bodyRangesList.toBodyRangeList(), + bodyRanges = editedContent.dataMessage?.bodyRanges.toBodyRangeList(), messageToEdit = originalMessageId ) val editMessageId = SignalDatabase.messages.insertMessageOutbox(editMessage, threadId, false, null) SignalDatabase.messages.markAsSent(editMessageId, true) - if (content.dataMessage.expireTimer > 0) { + if ((content.dataMessage?.expireTimer ?: 0) > 0) { SignalDatabase.messages.markExpireStarted(editMessageId, originalTimestamp) } testResult.collectLocal() @@ -167,7 +171,7 @@ class EditMessageSyncProcessorTest { fun runSync(messages: List) { messages.forEach { (envelope, content, metadata, serverDeliveredTimestamp) -> - if (content.hasSyncMessage()) { + if (content.syncMessage != null) { processorV2.process( envelope, content, diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt index 67b2f23e35..606631dd18 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessor__recipientStatusTest.kt @@ -1,13 +1,13 @@ package org.thoughtcrime.securesms.messages import androidx.test.ext.junit.runners.AndroidJUnit4 +import okio.ByteString.Companion.toByteString import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.thoughtcrime.securesms.database.GroupReceiptTable import org.thoughtcrime.securesms.database.SignalDatabase -import org.thoughtcrime.securesms.database.model.toProtoByteString import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.buildWith import org.thoughtcrime.securesms.testing.GroupTestingUtils import org.thoughtcrime.securesms.testing.GroupTestingUtils.asMember @@ -15,8 +15,8 @@ import org.thoughtcrime.securesms.testing.MessageContentFuzzer import org.thoughtcrime.securesms.testing.SignalActivityRule import org.thoughtcrime.securesms.testing.assertIs import org.thoughtcrime.securesms.util.MessageTableTestUtils -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2 +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.GroupContextV2 @Suppress("ClassName") @RunWith(AndroidJUnit4::class) @@ -41,9 +41,9 @@ class MessageContentProcessor__recipientStatusTest { @Test fun syncGroupSentTextMessageWithRecipientUpdateFollowup() { val (groupId, masterKey, groupRecipientId) = GroupTestingUtils.insertGroup(revision = 0, harness.self.asMember(), harness.others[0].asMember(), harness.others[1].asMember()) - val groupContextV2 = GroupContextV2.newBuilder().setRevision(0).setMasterKey(masterKey.serialize().toProtoByteString()).build() + val groupContextV2 = GroupContextV2.Builder().revision(0).masterKey(masterKey.serialize().toByteString()).build() - val initialTextMessage = DataMessage.newBuilder().buildWith { + val initialTextMessage = DataMessage.Builder().buildWith { body = MessageContentFuzzer.string() groupV2 = groupContextV2 timestamp = envelopeTimestamp diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt index 93e762c2c6..07233e48f7 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt @@ -6,7 +6,6 @@ import io.mockk.mockkObject import io.mockk.mockkStatic import io.mockk.unmockkStatic import okio.ByteString -import okio.ByteString.Companion.toByteString import org.junit.After import org.junit.Before import org.junit.Ignore @@ -26,7 +25,7 @@ import org.thoughtcrime.securesms.testing.Entry import org.thoughtcrime.securesms.testing.FakeClientHelpers import org.thoughtcrime.securesms.testing.SignalActivityRule import org.thoughtcrime.securesms.testing.awaitFor -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Envelope import org.whispersystems.signalservice.internal.websocket.WebSocketMessage import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage import java.util.regex.Pattern @@ -93,7 +92,7 @@ class MessageProcessingPerformanceTest { val messageCount = 100 val envelopes = generateInboundEnvelopes(bobClient, messageCount) val firstTimestamp = envelopes.first().timestamp - val lastTimestamp = envelopes.last().timestamp + val lastTimestamp = envelopes.last().timestamp ?: 0 // Inject the envelopes into the websocket Thread { @@ -190,7 +189,7 @@ class MessageProcessingPerformanceTest { path = "/api/v1/message", id = Random(System.currentTimeMillis()).nextLong(), headers = listOf("X-Signal-Timestamp: ${this.timestamp}"), - body = this.toByteArray().toByteString() + body = this.encodeByteString() ) ).encodeByteString() } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TestMessage.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TestMessage.kt index f3d0170f23..95acaba92a 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TestMessage.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TestMessage.kt @@ -1,11 +1,12 @@ package org.thoughtcrime.securesms.messages import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope data class TestMessage( - val envelope: SignalServiceProtos.Envelope, - val content: SignalServiceProtos.Content, + val envelope: Envelope, + val content: Content, val metadata: EnvelopeMetadata, val serverDeliveredTimestamp: Long ) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TimingMessageContentProcessor.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TimingMessageContentProcessor.kt index 86a318b4e7..20073a9453 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TimingMessageContentProcessor.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TimingMessageContentProcessor.kt @@ -5,7 +5,8 @@ import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.testing.LogPredicate import org.thoughtcrime.securesms.util.SignalLocalMetrics import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope class TimingMessageContentProcessor(context: Context) : MessageContentProcessor(context) { companion object { @@ -19,9 +20,9 @@ class TimingMessageContentProcessor(context: Context) : MessageContentProcessor( fun endTag(timestamp: Long) = "$timestamp end" } - override fun process(envelope: SignalServiceProtos.Envelope, content: SignalServiceProtos.Content, metadata: EnvelopeMetadata, serverDeliveredTimestamp: Long, processingEarlyContent: Boolean, localMetric: SignalLocalMetrics.MessageReceive?) { - Log.d(TAG, startTag(envelope.timestamp)) + override fun process(envelope: Envelope, content: Content, metadata: EnvelopeMetadata, serverDeliveredTimestamp: Long, processingEarlyContent: Boolean, localMetric: SignalLocalMetrics.MessageReceive?) { + Log.d(TAG, startTag(envelope.timestamp!!)) super.process(envelope, content, metadata, serverDeliveredTimestamp, processingEarlyContent, localMetric) - Log.d(TAG, endTag(envelope.timestamp)) + Log.d(TAG, endTag(envelope.timestamp!!)) } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt index 0977d99211..8eaf4ab865 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt @@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.testing.FakeClientHelpers.toEnvelope import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Envelope /** * Welcome to Alice's Client. diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt index b5e5ab133a..49d7b78ba2 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt @@ -31,11 +31,10 @@ import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.Envelope import java.util.Optional import java.util.UUID import java.util.concurrent.locks.ReentrantLock -import kotlin.UnsupportedOperationException /** * Welcome to Bob's Client. @@ -61,7 +60,7 @@ class BobClient(val serviceId: ServiceId, val e164: String, val identityKeyPair: } /** Inspired by SignalServiceMessageSender#getEncryptedMessage */ - fun encrypt(now: Long): SignalServiceProtos.Envelope { + fun encrypt(now: Long): Envelope { val envelopeContent = FakeClientHelpers.encryptedTextMessage(now) val cipher = SignalServiceCipher(serviceAddress, 1, aciStore, sessionLock, null) @@ -72,10 +71,10 @@ class BobClient(val serviceId: ServiceId, val e164: String, val identityKeyPair: } return cipher.encrypt(getAliceProtocolAddress(), getAliceUnidentifiedAccess(), envelopeContent) - .toEnvelope(envelopeContent.content.get().dataMessage.timestamp, getAliceServiceId()) + .toEnvelope(envelopeContent.content.get().dataMessage!!.timestamp!!, getAliceServiceId()) } - fun decrypt(envelope: SignalServiceProtos.Envelope, serverDeliveredTimestamp: Long) { + fun decrypt(envelope: Envelope, serverDeliveredTimestamp: Long) { val cipher = SignalServiceCipher(serviceAddress, 1, aciStore, sessionLock, UnidentifiedAccessUtil.getCertificateValidator()) cipher.decrypt(envelope, serverDeliveredTimestamp) } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/FakeClientHelpers.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/FakeClientHelpers.kt index da9aba40ae..d811829762 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/FakeClientHelpers.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/FakeClientHelpers.kt @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.testing +import okio.ByteString.Companion.toByteString import org.signal.libsignal.internal.Native import org.signal.libsignal.internal.NativeHandleGuard import org.signal.libsignal.metadata.certificate.CertificateValidator @@ -9,15 +10,16 @@ import org.signal.libsignal.protocol.ecc.Curve import org.signal.libsignal.protocol.ecc.ECKeyPair import org.signal.libsignal.protocol.ecc.ECPublicKey import org.signal.libsignal.zkgroup.profiles.ProfileKey -import org.thoughtcrime.securesms.database.model.toProtoByteString +import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.buildWith import org.whispersystems.signalservice.api.crypto.ContentHint import org.whispersystems.signalservice.api.crypto.EnvelopeContent import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.Envelope import org.whispersystems.signalservice.internal.push.OutgoingPushMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope import org.whispersystems.util.Base64 import java.util.Optional import java.util.UUID @@ -52,9 +54,9 @@ object FakeClientHelpers { } fun encryptedTextMessage(now: Long, message: String = "Test body message"): EnvelopeContent { - val content = SignalServiceProtos.Content.newBuilder().apply { - setDataMessage( - SignalServiceProtos.DataMessage.newBuilder().apply { + val content = Content.Builder().apply { + dataMessage( + DataMessage.Builder().buildWith { body = message timestamp = now } @@ -64,16 +66,16 @@ object FakeClientHelpers { } fun OutgoingPushMessage.toEnvelope(timestamp: Long, destination: ServiceId): Envelope { - return Envelope.newBuilder() - .setType(Envelope.Type.valueOf(this.type)) - .setSourceDevice(1) - .setTimestamp(timestamp) - .setServerTimestamp(timestamp + 1) - .setDestinationServiceId(destination.toString()) - .setServerGuid(UUID.randomUUID().toString()) - .setContent(Base64.decode(this.content).toProtoByteString()) - .setUrgent(true) - .setStory(false) + return Envelope.Builder() + .type(Envelope.Type.fromValue(this.type)) + .sourceDevice(1) + .timestamp(timestamp) + .serverTimestamp(timestamp + 1) + .destinationServiceId(destination.toString()) + .serverGuid(UUID.randomUUID().toString()) + .content(Base64.decode(this.content).toByteString()) + .urgent(true) + .story(false) .build() } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt index 1523efef82..284899713b 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt @@ -16,19 +16,19 @@ import kotlin.random.Random */ object GroupTestingUtils { fun member(aci: ACI, revision: Int = 0, role: Member.Role = Member.Role.ADMINISTRATOR): DecryptedMember { - return DecryptedMember.newBuilder() - .setAciBytes(aci.toByteString()) - .setJoinedAtRevision(revision) - .setRole(role) + return DecryptedMember.Builder() + .aciBytes(aci.toByteString()) + .joinedAtRevision(revision) + .role(role) .build() } fun insertGroup(revision: Int = 0, vararg members: DecryptedMember): TestGroupInfo { val groupMasterKey = GroupMasterKey(Random.nextBytes(GroupMasterKey.SIZE)) - val decryptedGroupState = DecryptedGroup.newBuilder() - .addAllMembers(members.toList()) - .setRevision(revision) - .setTitle(MessageContentFuzzer.string()) + val decryptedGroupState = DecryptedGroup.Builder() + .members(members.toList()) + .revision(revision) + .title(MessageContentFuzzer.string()) .build() val groupId = SignalDatabase.groups.create(groupMasterKey, decryptedGroupState)!! diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt index 442f4b54ed..bc2bc11dd7 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MessageContentFuzzer.kt @@ -1,21 +1,20 @@ package org.thoughtcrime.securesms.testing -import com.google.protobuf.ByteString -import org.thoughtcrime.securesms.database.model.toProtoByteString +import okio.ByteString +import okio.ByteString.Companion.toByteString import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.buildWith import org.thoughtcrime.securesms.messages.TestMessage import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.api.util.UuidUtil -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2 -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage +import org.whispersystems.signalservice.internal.push.AttachmentPointer +import org.whispersystems.signalservice.internal.push.BodyRange +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.GroupContextV2 +import org.whispersystems.signalservice.internal.push.SyncMessage import java.util.UUID import kotlin.random.Random import kotlin.random.nextInt @@ -35,10 +34,10 @@ object MessageContentFuzzer { * Create an [Envelope]. */ fun envelope(timestamp: Long): Envelope { - return Envelope.newBuilder() - .setTimestamp(timestamp) - .setServerTimestamp(timestamp + 5) - .setServerGuidBytes(UuidUtil.toByteString(UUID.randomUUID())) + return Envelope.Builder() + .timestamp(timestamp) + .serverTimestamp(timestamp + 5) + .serverGuid(UUID.randomUUID().toString()) .build() } @@ -62,20 +61,22 @@ object MessageContentFuzzer { * - Bold style body ranges */ fun fuzzTextMessage(groupContextV2: GroupContextV2? = null): Content { - return Content.newBuilder() - .setDataMessage( - DataMessage.newBuilder().buildWith { + return Content.Builder() + .dataMessage( + DataMessage.Builder().buildWith { body = string() if (random.nextBoolean()) { expireTimer = random.nextInt(0..28.days.inWholeSeconds.toInt()) } if (random.nextBoolean()) { - addBodyRanges( - SignalServiceProtos.BodyRange.newBuilder().buildWith { - start = 0 - length = 1 - style = SignalServiceProtos.BodyRange.Style.BOLD - } + bodyRanges( + listOf( + BodyRange.Builder().buildWith { + start = 0 + length = 1 + style = BodyRange.Style.BOLD + } + ) ) } if (groupContextV2 != null) { @@ -95,16 +96,16 @@ object MessageContentFuzzer { recipientUpdate: Boolean = false ): Content { return Content - .newBuilder() - .setSyncMessage( - SyncMessage.newBuilder().buildWith { - sent = SyncMessage.Sent.newBuilder().buildWith { + .Builder() + .syncMessage( + SyncMessage.Builder().buildWith { + sent = SyncMessage.Sent.Builder().buildWith { timestamp = textMessage.timestamp message = textMessage isRecipientUpdate = recipientUpdate - addAllUnidentifiedStatus( + unidentifiedStatus( deliveredTo.map { - SyncMessage.Sent.UnidentifiedDeliveryStatus.newBuilder().buildWith { + SyncMessage.Sent.UnidentifiedDeliveryStatus.Builder().buildWith { destinationServiceId = Recipient.resolved(it).requireServiceId().toString() unidentified = true } @@ -123,9 +124,9 @@ object MessageContentFuzzer { * - A message with 0-2 attachment pointers and may contain a text body */ fun fuzzMediaMessageWithBody(quoteAble: List = emptyList()): Content { - return Content.newBuilder() - .setDataMessage( - DataMessage.newBuilder().buildWith { + return Content.Builder() + .dataMessage( + DataMessage.Builder().buildWith { if (random.nextBoolean()) { body = string() } @@ -133,28 +134,28 @@ object MessageContentFuzzer { if (random.nextBoolean() && quoteAble.isNotEmpty()) { body = string() val quoted = quoteAble.random(random) - quote = DataMessage.Quote.newBuilder().buildWith { + quote = DataMessage.Quote.Builder().buildWith { id = quoted.envelope.timestamp authorAci = quoted.metadata.sourceServiceId.toString() - text = quoted.content.dataMessage.body - addAllAttachments(quoted.content.dataMessage.attachmentsList) - addAllBodyRanges(quoted.content.dataMessage.bodyRangesList) + text = quoted.content.dataMessage?.body + attachments(quoted.content.dataMessage?.attachments ?: emptyList()) + bodyRanges(quoted.content.dataMessage?.bodyRanges ?: emptyList()) type = DataMessage.Quote.Type.NORMAL } } if (random.nextFloat() < 0.1 && quoteAble.isNotEmpty()) { val quoted = quoteAble.random(random) - quote = DataMessage.Quote.newBuilder().buildWith { - id = random.nextLong(quoted.envelope.timestamp - 1000000, quoted.envelope.timestamp) + quote = DataMessage.Quote.Builder().buildWith { + id = random.nextLong(quoted.envelope.timestamp!! - 1000000, quoted.envelope.timestamp!!) authorAci = quoted.metadata.sourceServiceId.toString() - text = quoted.content.dataMessage.body + text = quoted.content.dataMessage?.body } } if (random.nextFloat() < 0.25) { val total = random.nextInt(1, 2) - (0..total).forEach { _ -> addAttachments(attachmentPointer()) } + attachments((0..total).map { attachmentPointer() }) } } ) @@ -166,12 +167,12 @@ object MessageContentFuzzer { * - A reaction to a prior message */ fun fuzzMediaMessageNoContent(previousMessages: List = emptyList()): Content { - return Content.newBuilder() - .setDataMessage( - DataMessage.newBuilder().buildWith { + return Content.Builder() + .dataMessage( + DataMessage.Builder().buildWith { if (random.nextFloat() < 0.25) { val reactTo = previousMessages.random(random) - reaction = DataMessage.Reaction.newBuilder().buildWith { + reaction = DataMessage.Reaction.Builder().buildWith { emoji = emojis.random(random) remove = false targetAuthorAci = reactTo.metadata.sourceServiceId.toString() @@ -187,15 +188,15 @@ object MessageContentFuzzer { * - A sticker */ fun fuzzMediaMessageNoText(previousMessages: List = emptyList()): Content { - return Content.newBuilder() - .setDataMessage( - DataMessage.newBuilder().buildWith { + return Content.Builder() + .dataMessage( + DataMessage.Builder().buildWith { if (random.nextFloat() < 0.9) { - sticker = DataMessage.Sticker.newBuilder().buildWith { + sticker = DataMessage.Sticker.Builder().buildWith { packId = byteString(length = 24) packKey = byteString(length = 128) stickerId = random.nextInt() - data = attachmentPointer() + data_ = attachmentPointer() emoji = emojis.random(random) } } @@ -223,14 +224,14 @@ object MessageContentFuzzer { * Generate a random [ByteString]. */ fun byteString(length: Int = 512): ByteString { - return random.nextBytes(length).toProtoByteString() + return random.nextBytes(length).toByteString() } /** * Generate a random [AttachmentPointer]. */ fun attachmentPointer(): AttachmentPointer { - return AttachmentPointer.newBuilder().run { + return AttachmentPointer.Builder().run { cdnKey = string() contentType = mediaTypes.random(random) key = byteString() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt deleted file mode 100644 index 706e589eea..0000000000 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt +++ /dev/null @@ -1,70 +0,0 @@ -package org.thoughtcrime.securesms.testing - -import com.google.protobuf.ByteString -import org.signal.libsignal.zkgroup.groups.GroupMasterKey -import org.whispersystems.signalservice.api.push.ServiceId.ACI -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2 -import org.whispersystems.signalservice.internal.serialize.protos.AddressProto -import org.whispersystems.signalservice.internal.serialize.protos.MetadataProto -import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceContentProto -import java.util.UUID -import kotlin.random.Random - -class TestProtos private constructor() { - fun address( - uuid: UUID = UUID.randomUUID() - ): AddressProto.Builder { - return AddressProto.newBuilder() - .setUuid(ACI.from(uuid).toByteString()) - } - - fun metadata( - address: AddressProto = address().build() - ): MetadataProto.Builder { - return MetadataProto.newBuilder() - .setAddress(address) - } - - fun groupContextV2( - revision: Int = 0, - masterKeyBytes: ByteArray = Random.Default.nextBytes(GroupMasterKey.SIZE) - ): GroupContextV2.Builder { - return GroupContextV2.newBuilder() - .setRevision(revision) - .setMasterKey(ByteString.copyFrom(masterKeyBytes)) - } - - fun storyContext( - sentTimestamp: Long = Random.nextLong(), - authorUuid: String = UUID.randomUUID().toString() - ): DataMessage.StoryContext.Builder { - return DataMessage.StoryContext.newBuilder() - .setAuthorAci(authorUuid) - .setSentTimestamp(sentTimestamp) - } - - fun dataMessage(): DataMessage.Builder { - return DataMessage.newBuilder() - } - - fun content(): SignalServiceProtos.Content.Builder { - return SignalServiceProtos.Content.newBuilder() - } - - fun serviceContent( - localAddress: AddressProto = address().build(), - metadata: MetadataProto = metadata().build() - ): SignalServiceContentProto.Builder { - return SignalServiceContentProto.newBuilder() - .setLocalAddress(localAddress) - .setMetadata(metadata) - } - - companion object { - fun build(buildFn: TestProtos.() -> T): T { - return TestProtos().buildFn() - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/SvrAuthTokens.kt b/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/SvrAuthTokens.kt index 7c530c7b2b..94525ea16d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/SvrAuthTokens.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/SvrAuthTokens.kt @@ -1,10 +1,10 @@ package org.thoughtcrime.securesms.absbackup.backupables -import com.google.protobuf.InvalidProtocolBufferException import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.absbackup.AndroidBackupItem import org.thoughtcrime.securesms.absbackup.protos.SvrAuthToken import org.thoughtcrime.securesms.keyvalue.SignalStore +import java.io.IOException /** * This backs up the not-secret KBS Auth tokens, which can be combined with a PIN to prove ownership of a phone number in order to complete the registration process. @@ -30,7 +30,7 @@ object SvrAuthTokens : AndroidBackupItem { val proto = SvrAuthToken.ADAPTER.decode(data) SignalStore.svr().putAuthTokenList(proto.tokens) - } catch (e: InvalidProtocolBufferException) { + } catch (e: IOException) { Log.w(TAG, "Cannot restore KbsAuthToken from backup service.") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.java b/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.java index 0c3f80e526..ecb616642b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.java @@ -13,7 +13,7 @@ import org.whispersystems.signalservice.api.InvalidMessageStructureException; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.util.AttachmentPointerUtil; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.DataMessage; import java.util.LinkedList; import java.util.List; @@ -152,18 +152,18 @@ public class PointerAttachment extends Attachment { null)); } - public static Optional forPointer(SignalServiceProtos.DataMessage.Quote.QuotedAttachment quotedAttachment) { + public static Optional forPointer(DataMessage.Quote.QuotedAttachment quotedAttachment) { SignalServiceAttachment thumbnail; try { - thumbnail = quotedAttachment.hasThumbnail() ? AttachmentPointerUtil.createSignalAttachmentPointer(quotedAttachment.getThumbnail()) : null; + thumbnail = quotedAttachment.thumbnail != null ? AttachmentPointerUtil.createSignalAttachmentPointer(quotedAttachment.thumbnail) : null; } catch (InvalidMessageStructureException e) { return Optional.empty(); } - return Optional.of(new PointerAttachment(quotedAttachment.getContentType(), + return Optional.of(new PointerAttachment(quotedAttachment.contentType, AttachmentTable.TRANSFER_PROGRESS_PENDING, thumbnail != null ? thumbnail.asPointer().getSize().orElse(0) : 0, - quotedAttachment.getFileName(), + quotedAttachment.fileName, thumbnail != null ? thumbnail.asPointer().getCdnNumber() : 0, thumbnail != null ? thumbnail.asPointer().getRemoteId().toString() : "0", thumbnail != null && thumbnail.asPointer().getKey() != null ? Base64.encodeBytes(thumbnail.asPointer().getKey()) : null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioFileInfo.java b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioFileInfo.java index 248d1a8b8a..1e0da14c47 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioFileInfo.java +++ b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioFileInfo.java @@ -2,19 +2,19 @@ package org.thoughtcrime.securesms.audio; import androidx.annotation.NonNull; -import com.google.protobuf.ByteString; - import org.thoughtcrime.securesms.database.model.databaseprotos.AudioWaveFormData; import java.util.concurrent.TimeUnit; +import okio.ByteString; + public class AudioFileInfo { private final long durationUs; private final byte[] waveFormBytes; private final float[] waveForm; public static @NonNull AudioFileInfo fromDatabaseProtobuf(@NonNull AudioWaveFormData audioWaveForm) { - return new AudioFileInfo(audioWaveForm.getDurationUs(), audioWaveForm.getWaveForm().toByteArray()); + return new AudioFileInfo(audioWaveForm.durationUs, audioWaveForm.waveForm.toByteArray()); } AudioFileInfo(long durationUs, byte[] waveFormBytes) { @@ -37,9 +37,9 @@ public class AudioFileInfo { } public @NonNull AudioWaveFormData toDatabaseProtobuf() { - return AudioWaveFormData.newBuilder() - .setDurationUs(durationUs) - .setWaveForm(ByteString.copyFrom(waveFormBytes)) - .build(); + return new AudioWaveFormData.Builder() + .durationUs(durationUs) + .waveForm(ByteString.of(waveFormBytes)) + .build(); } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioHash.java b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioHash.java index 6550fe37ff..73c7f48ee3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioHash.java +++ b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioHash.java @@ -22,13 +22,13 @@ public final class AudioHash { } public AudioHash(@NonNull AudioWaveFormData audioWaveForm) { - this(Base64.encodeBytes(audioWaveForm.toByteArray()), audioWaveForm); + this(Base64.encodeBytes(audioWaveForm.encode()), audioWaveForm); } public static @Nullable AudioHash parseOrNull(@Nullable String hash) { if (hash == null) return null; try { - return new AudioHash(hash, AudioWaveFormData.parseFrom(Base64.decode(hash))); + return new AudioHash(hash, AudioWaveFormData.ADAPTER.decode(Base64.decode(hash))); } catch (IOException e) { return null; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioWaveForms.kt b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioWaveForms.kt index 28a8414422..3e00cfb0ec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/audio/AudioWaveForms.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/audio/AudioWaveForms.kt @@ -107,7 +107,7 @@ object AudioWaveForms { private fun generateWaveForm(context: Context, uri: Uri, cacheKey: String, attachmentId: AttachmentId): CacheCheckResult { try { val startTime = System.currentTimeMillis() - SignalDatabase.attachments.writeAudioHash(attachmentId, AudioWaveFormData.getDefaultInstance()) + SignalDatabase.attachments.writeAudioHash(attachmentId, AudioWaveFormData()) Log.i(TAG, "Starting wave form generation ($cacheKey)") val fileInfo: AudioFileInfo = AudioWaveFormGenerator.generateWaveForm(context, uri) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/Badges.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/Badges.kt index 48f4b887c4..9a994b3e90 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/Badges.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/Badges.kt @@ -101,16 +101,16 @@ object Badges { @JvmStatic fun toDatabaseBadge(badge: Badge): BadgeList.Badge { - return BadgeList.Badge.newBuilder() - .setId(badge.id) - .setCategory(badge.category.code) - .setDescription(badge.description) - .setExpiration(badge.expirationTimestamp) - .setVisible(badge.visible) - .setName(badge.name) - .setImageUrl(badge.imageUrl.toString()) - .setImageDensity(badge.imageDensity) - .build() + return BadgeList.Badge( + id = badge.id, + category = badge.category.code, + description = badge.description, + expiration = badge.expirationTimestamp, + visible = badge.visible, + name = badge.name, + imageUrl = badge.imageUrl.toString(), + imageDensity = badge.imageDensity + ) } @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt index bcdf62baaf..da3a724d4c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt @@ -79,12 +79,11 @@ class GiftMessageView @JvmOverloads constructor( } actionView.setText( - when (giftBadge.redemptionState ?: GiftBadge.RedemptionState.UNRECOGNIZED) { + when (giftBadge.redemptionState) { GiftBadge.RedemptionState.PENDING -> R.string.GiftMessageView__redeem GiftBadge.RedemptionState.STARTED -> R.string.GiftMessageView__redeeming GiftBadge.RedemptionState.REDEEMED -> R.string.GiftMessageView__redeemed GiftBadge.RedemptionState.FAILED -> R.string.GiftMessageView__redeem - GiftBadge.RedemptionState.UNRECOGNIZED -> R.string.GiftMessageView__redeem } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt index cd2d4d8cb1..43672fbe38 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt @@ -32,7 +32,7 @@ object Gifts { ): OutgoingMessage { return OutgoingMessage( threadRecipient = recipient, - body = Base64.encodeBytes(giftBadge.toByteArray()), + body = Base64.encodeBytes(giftBadge.encode()), isSecure = true, sentTimeMillis = sentTimestamp, expiresIn = expiresIn, diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt index d260eb2972..ac63ddb1fb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt @@ -63,7 +63,7 @@ class ViewReceivedGiftBottomSheet : DSLSettingsBottomSheetFragment() { ViewReceivedGiftBottomSheet().apply { arguments = Bundle().apply { putParcelable(ARG_SENT_FROM, messageRecord.fromRecipient.id) - putByteArray(ARG_GIFT_BADGE, messageRecord.giftBadge!!.toByteArray()) + putByteArray(ARG_GIFT_BADGE, messageRecord.giftBadge!!.encode()) putLong(ARG_MESSAGE_ID, messageRecord.id) } show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt index dae757c06f..3b55466940 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt @@ -34,7 +34,7 @@ class ViewSentGiftBottomSheet : DSLSettingsBottomSheetFragment() { ViewSentGiftBottomSheet().apply { arguments = Bundle().apply { putParcelable(ARG_SENT_TO, messageRecord.toRecipient.id) - putByteArray(ARG_GIFT_BADGE, messageRecord.giftBadge!!.toByteArray()) + putByteArray(ARG_GIFT_BADGE, messageRecord.giftBadge!!.encode()) } show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) } @@ -45,7 +45,7 @@ class ViewSentGiftBottomSheet : DSLSettingsBottomSheetFragment() { get() = requireArguments().getParcelableCompat(ARG_SENT_TO, RecipientId::class.java)!! private val giftBadge: GiftBadge - get() = GiftBadge.parseFrom(requireArguments().getByteArray(ARG_GIFT_BADGE)) + get() = GiftBadge.ADAPTER.decode(requireArguments().getByteArray(ARG_GIFT_BADGE)!!) private val lifecycleDisposable = LifecycleDisposable() diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt index c3c46fefb5..89f2cf4a5a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt @@ -93,11 +93,11 @@ sealed class CallLogRow { return FULL } - if (groupCallUpdateDetails.inCallUuidsList.contains(Recipient.self().requireAci().rawUuid.toString())) { + if (groupCallUpdateDetails.inCallUuids.contains(Recipient.self().requireAci().rawUuid.toString())) { return LOCAL_USER_JOINED } - return if (groupCallUpdateDetails.inCallUuidsCount > 0) { + return if (groupCallUpdateDetails.inCallUuids.isNotEmpty()) { ACTIVE } else { NONE diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt index 4699c3cc28..0d3fe04860 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt @@ -4,6 +4,7 @@ import androidx.annotation.WorkerThread import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers +import okio.ByteString.Companion.toByteString import org.signal.core.util.logging.Log import org.signal.libsignal.protocol.IdentityKeyPair import org.signal.libsignal.protocol.SignalProtocolAddress @@ -17,7 +18,6 @@ import org.thoughtcrime.securesms.crypto.PreKeyUtil import org.thoughtcrime.securesms.database.IdentityTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.databaseprotos.PendingChangeNumberMetadata -import org.thoughtcrime.securesms.database.model.toProtoByteString import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobs.RefreshAttributesJob import org.thoughtcrime.securesms.keyvalue.CertificateType @@ -42,7 +42,7 @@ import org.whispersystems.signalservice.internal.ServiceResponse import org.whispersystems.signalservice.internal.push.KyberPreKeyEntity import org.whispersystems.signalservice.internal.push.OutgoingPushMessage import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage +import org.whispersystems.signalservice.internal.push.SyncMessage import org.whispersystems.signalservice.internal.push.VerifyAccountResponse import org.whispersystems.signalservice.internal.push.WhoAmIResponse import org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException @@ -367,13 +367,13 @@ class ChangeNumberRepository( // Device Messages if (deviceId != primaryDeviceId) { - val pniChangeNumber = SyncMessage.PniChangeNumber.newBuilder() - .setIdentityKeyPair(pniIdentity.serialize().toProtoByteString()) - .setSignedPreKey(signedPreKeyRecord.serialize().toProtoByteString()) - .setLastResortKyberPreKey(lastResortKyberPreKeyRecord.serialize().toProtoByteString()) - .setRegistrationId(pniRegistrationId) - .setNewE164(newE164) - .build() + val pniChangeNumber = SyncMessage.PniChangeNumber( + identityKeyPair = pniIdentity.serialize().toByteString(), + signedPreKey = signedPreKeyRecord.serialize().toByteString(), + lastResortKyberPreKey = lastResortKyberPreKeyRecord.serialize().toByteString(), + registrationId = pniRegistrationId, + newE164 = newE164 + ) deviceMessages += messageSender.getEncryptedSyncPniInitializeDeviceMessage(deviceId, pniChangeNumber) } @@ -391,12 +391,12 @@ class ChangeNumberRepository( pniRegistrationIds.mapKeys { it.key.toString() } ) - val metadata = PendingChangeNumberMetadata.newBuilder() - .setPreviousPni(SignalStore.account().pni!!.toByteString()) - .setPniIdentityKeyPair(pniIdentity.serialize().toProtoByteString()) - .setPniRegistrationId(pniRegistrationIds[primaryDeviceId]!!) - .setPniSignedPreKeyId(devicePniSignedPreKeys[primaryDeviceId]!!.keyId) - .build() + val metadata = PendingChangeNumberMetadata( + previousPni = SignalStore.account().pni!!.toByteString(), + pniIdentityKeyPair = pniIdentity.serialize().toByteString(), + pniRegistrationId = pniRegistrationIds[primaryDeviceId]!!, + pniSignedPreKeyId = devicePniSignedPreKeys[primaryDeviceId]!!.keyId + ) return ChangeNumberRequestData(request, metadata) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsRepository.kt index edbb91f434..6ca689b385 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsRepository.kt @@ -32,7 +32,7 @@ class InternalSettingsRepository(context: Context) { val title = "Release Note Title" val bodyText = "Release note body. Aren't I awesome?" val body = "$title\n\n$bodyText" - val bodyRangeList = BodyRangeList.newBuilder() + val bodyRangeList = BodyRangeList.Builder() .addStyle(BodyRangeList.BodyRange.Style.BOLD, 0, title.length) val recipientId = SignalStore.releaseChannelValues().releaseChannelRecipientId!! diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsRepository.kt index c79d6fbc10..0bff6d921c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsRepository.kt @@ -10,7 +10,6 @@ import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.logging.Log import org.signal.storageservice.protos.groups.local.DecryptedGroup -import org.signal.storageservice.protos.groups.local.DecryptedPendingMember import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery import org.thoughtcrime.securesms.database.CallTable import org.thoughtcrime.securesms.database.MediaTable @@ -152,9 +151,9 @@ class ConversationSettingsRepository( consumer( if (groupRecord.isV2Group) { val decryptedGroup: DecryptedGroup = groupRecord.requireV2GroupProperties().decryptedGroup - val pendingMembers: List = decryptedGroup.pendingMembersList - .map(DecryptedPendingMember::getServiceIdBytes) - .map(GroupProtoUtil::serviceIdBinaryToRecipientId) + val pendingMembers: List = decryptedGroup.pendingMembers + .map { m -> m.serviceIdBytes } + .map { s -> GroupProtoUtil.serviceIdBinaryToRecipientId(s) } val members = mutableListOf() diff --git a/app/src/main/java/org/thoughtcrime/securesms/contactshare/ContactModelMapper.java b/app/src/main/java/org/thoughtcrime/securesms/contactshare/ContactModelMapper.java index f87438f556..60b2311ad9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contactshare/ContactModelMapper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/contactshare/ContactModelMapper.java @@ -9,7 +9,7 @@ import org.whispersystems.signalservice.api.InvalidMessageStructureException; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.util.AttachmentPointerUtil; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.DataMessage; import java.util.ArrayList; import java.util.LinkedList; @@ -125,47 +125,47 @@ public class ContactModelMapper { return new Contact(name, sharedContact.getOrganization().orElse(null), phoneNumbers, emails, postalAddresses, avatar); } - public static Contact remoteToLocal(@NonNull SignalServiceProtos.DataMessage.Contact contact) { - Name name = new Name(contact.getName().getDisplayName(), - contact.getName().getGivenName(), - contact.getName().getFamilyName(), - contact.getName().getPrefix(), - contact.getName().getSuffix(), - contact.getName().getMiddleName()); + public static Contact remoteToLocal(@NonNull DataMessage.Contact contact) { + Name name = new Name(contact.name.displayName, + contact.name.givenName, + contact.name.familyName, + contact.name.prefix, + contact.name.suffix, + contact.name.middleName); - List phoneNumbers = new ArrayList<>(contact.getNumberCount()); - for (SignalServiceProtos.DataMessage.Contact.Phone phone : contact.getNumberList()) { - phoneNumbers.add(new Phone(phone.getValue(), - remoteToLocalType(phone.getType()), - phone.getLabel())); + List phoneNumbers = new ArrayList<>(contact.number.size()); + for (DataMessage.Contact.Phone phone : contact.number) { + phoneNumbers.add(new Phone(phone.value_, + remoteToLocalType(phone.type), + phone.label)); } - List emails = new ArrayList<>(contact.getEmailCount()); - for (SignalServiceProtos.DataMessage.Contact.Email email : contact.getEmailList()) { - emails.add(new Email(email.getValue(), - remoteToLocalType(email.getType()), - email.getLabel())); + List emails = new ArrayList<>(contact.email.size()); + for (DataMessage.Contact.Email email : contact.email) { + emails.add(new Email(email.value_, + remoteToLocalType(email.type), + email.label)); } - List postalAddresses = new ArrayList<>(contact.getAddressCount()); - for (SignalServiceProtos.DataMessage.Contact.PostalAddress postalAddress : contact.getAddressList()) { - postalAddresses.add(new PostalAddress(remoteToLocalType(postalAddress.getType()), - postalAddress.getLabel(), - postalAddress.getStreet(), - postalAddress.getPobox(), - postalAddress.getNeighborhood(), - postalAddress.getCity(), - postalAddress.getRegion(), - postalAddress.getPostcode(), - postalAddress.getCountry())); + List postalAddresses = new ArrayList<>(contact.address.size()); + for (DataMessage.Contact.PostalAddress postalAddress : contact.address) { + postalAddresses.add(new PostalAddress(remoteToLocalType(postalAddress.type), + postalAddress.label, + postalAddress.street, + postalAddress.pobox, + postalAddress.neighborhood, + postalAddress.city, + postalAddress.region, + postalAddress.postcode, + postalAddress.country)); } Avatar avatar = null; - if (contact.hasAvatar()) { + if (contact.avatar != null) { try { - SignalServiceAttachmentPointer attachmentPointer = AttachmentPointerUtil.createSignalAttachmentPointer(contact.getAvatar().getAvatar()); + SignalServiceAttachmentPointer attachmentPointer = AttachmentPointerUtil.createSignalAttachmentPointer(contact.avatar.avatar); Attachment attachment = PointerAttachment.forPointer(Optional.of(attachmentPointer.asPointer())).get(); - boolean isProfile = contact.getAvatar().getIsProfile(); + boolean isProfile = contact.avatar.isProfile; avatar = new Avatar(null, attachment, isProfile); } catch (InvalidMessageStructureException e) { @@ -173,7 +173,7 @@ public class ContactModelMapper { } } - return new Contact(name, contact.getOrganization(), phoneNumbers, emails, postalAddresses, avatar); + return new Contact(name, contact.organization, phoneNumbers, emails, postalAddresses, avatar); } private static Phone.Type remoteToLocalType(SharedContact.Phone.Type type) { @@ -185,7 +185,7 @@ public class ContactModelMapper { } } - private static Phone.Type remoteToLocalType(SignalServiceProtos.DataMessage.Contact.Phone.Type type) { + private static Phone.Type remoteToLocalType(DataMessage.Contact.Phone.Type type) { switch (type) { case HOME: return Phone.Type.HOME; case MOBILE: return Phone.Type.MOBILE; @@ -203,7 +203,7 @@ public class ContactModelMapper { } } - private static Email.Type remoteToLocalType(SignalServiceProtos.DataMessage.Contact.Email.Type type) { + private static Email.Type remoteToLocalType(DataMessage.Contact.Email.Type type) { switch (type) { case HOME: return Email.Type.HOME; case MOBILE: return Email.Type.MOBILE; @@ -220,7 +220,7 @@ public class ContactModelMapper { } } - private static PostalAddress.Type remoteToLocalType(SignalServiceProtos.DataMessage.Contact.PostalAddress.Type type) { + private static PostalAddress.Type remoteToLocalType(DataMessage.Contact.PostalAddress.Type type) { switch (type) { case HOME: return PostalAddress.Type.HOME; case WORK: return PostalAddress.Type.WORK; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 8a2eec0ffe..bde2d8016c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -1060,10 +1060,10 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (conversationMessage.getBottomButton() != null) { callToActionStub.get().setVisibility(View.VISIBLE); - callToActionStub.get().setText(conversationMessage.getBottomButton().getLabel()); + callToActionStub.get().setText(conversationMessage.getBottomButton().label); callToActionStub.get().setOnClickListener(v -> { if (eventListener != null) { - eventListener.onCallToAction(conversationMessage.getBottomButton().getAction()); + eventListener.onCallToAction(conversationMessage.getBottomButton().action); } }); } else if (callToActionStub.resolved()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index b61aa6d0a9..73563fa42f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -454,7 +454,7 @@ public final class ConversationUpdateItem extends FrameLayout if (Util.hasItems(acis)) { if (acis.contains(SignalStore.account().requireAci())) { text = R.string.ConversationUpdateItem_return_to_call; - } else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).getIsCallFull()) { + } else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).isCallFull) { text = R.string.ConversationUpdateItem_call_is_full; } else { text = R.string.ConversationUpdateItem_join_call; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageStyler.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageStyler.kt index 9f4833ba01..70e904323a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageStyler.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageStyler.kt @@ -63,13 +63,13 @@ object MessageStyler { var bottomButton: BodyRange.Button? = null messageRanges - .rangesList + .ranges .filter { r -> r.start >= 0 && r.start < span.length && r.start + r.length >= 0 } .forEach { range -> val start = range.start val end = (range.start + range.length).coerceAtMost(span.length) - if (range.hasStyle()) { + if (range.style != null) { val styleSpan: Any? = when (range.style) { BodyRange.Style.BOLD -> boldStyle() BodyRange.Style.ITALIC -> italicStyle() @@ -90,10 +90,10 @@ object MessageStyler { span.setSpan(styleSpan, start, end, SPAN_FLAGS) appliedStyle = true } - } else if (range.hasLink() && range.link != null) { + } else if (range.link != null) { span.setSpan(PlaceholderURLSpan(range.link), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) hasLinks = true - } else if (range.hasButton() && range.button != null) { + } else if (range.button != null) { bottomButton = range.button } } @@ -245,7 +245,7 @@ object MessageStyler { } if (spanLength > 0 && style != null) { - BodyRange.newBuilder().setStart(spanStart).setLength(spanLength).setStyle(style).build() + BodyRange(start = spanStart, length = spanLength, style = style) } else { null } @@ -255,7 +255,7 @@ object MessageStyler { } return if (bodyRanges.isNotEmpty()) { - BodyRangeList.newBuilder().addAllRanges(bodyRanges).build() + BodyRangeList(ranges = bodyRanges) } else { null } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt index b2b4bffb8c..8d0c92a187 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt @@ -73,20 +73,20 @@ class ChatColors( } fun serialize(): ChatColor { - val builder: ChatColor.Builder = ChatColor.newBuilder() + val builder: ChatColor.Builder = ChatColor.Builder() if (linearGradient != null) { - val gradientBuilder = ChatColor.LinearGradient.newBuilder() + val gradientBuilder = ChatColor.LinearGradient.Builder() gradientBuilder.rotation = linearGradient.degrees - linearGradient.colors.forEach { gradientBuilder.addColors(it) } - linearGradient.positions.forEach { gradientBuilder.addPositions(it) } + gradientBuilder.colors = linearGradient.colors.toList() + gradientBuilder.positions = linearGradient.positions.toList() - builder.setLinearGradient(gradientBuilder) + builder.linearGradient(gradientBuilder.build()) } if (singleColor != null) { - builder.setSingleColor(ChatColor.SingleColor.newBuilder().setColor(singleColor)) + builder.singleColor(ChatColor.SingleColor.Builder().color(singleColor).build()) } return builder.build() @@ -142,18 +142,18 @@ class ChatColors( companion object { @JvmStatic fun forChatColor(id: Id, chatColor: ChatColor): ChatColors { - assert(chatColor.hasSingleColor() xor chatColor.hasLinearGradient()) + assert((chatColor.singleColor != null) xor (chatColor.linearGradient != null)) - return if (chatColor.hasLinearGradient()) { + return if (chatColor.linearGradient != null) { val linearGradient = LinearGradient( chatColor.linearGradient.rotation, - chatColor.linearGradient.colorsList.toIntArray(), - chatColor.linearGradient.positionsList.toFloatArray() + chatColor.linearGradient.colors.toIntArray(), + chatColor.linearGradient.positions.toFloatArray() ) forGradient(id, linearGradient) } else { - val singleColor = chatColor.singleColor.color + val singleColor = chatColor.singleColor!!.color forColor(id, singleColor) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt index 21da7bd5db..53f15a8b34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt @@ -191,7 +191,7 @@ class DraftRepository( var updatedText: Spannable? = null if (textDraft != null && bodyRangesDraft != null) { - val bodyRanges: BodyRangeList = BodyRangeList.parseFrom(Base64.decodeOrThrow(bodyRangesDraft.value)) + val bodyRanges: BodyRangeList = BodyRangeList.ADAPTER.decode(Base64.decodeOrThrow(bodyRangesDraft.value)) val mentions: List = MentionUtil.bodyRangeListToMentions(bodyRanges) val updated = MentionUtil.updateBodyAndMentionsWithDisplayNames(context, textDraft.value, mentions) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt index 7cde31af0e..709fd450a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt @@ -62,7 +62,7 @@ class DraftViewModel @JvmOverloads constructor( } else if (mentionRanges == null) { styleBodyRanges } else { - styleBodyRanges.toBuilder().addAllRanges(mentionRanges.rangesList).build() + styleBodyRanges.newBuilder().apply { ranges += mentionRanges.ranges }.build() } saveDrafts(it.copy(textDraft = text.toTextDraft(), bodyRangesDraft = bodyRanges?.toDraft(), messageEditDraft = Draft(Draft.MESSAGE_EDIT, messageId.serialize()))) @@ -84,7 +84,7 @@ class DraftViewModel @JvmOverloads constructor( } else if (mentionRanges == null) { styleBodyRanges } else { - styleBodyRanges.toBuilder().addAllRanges(mentionRanges.rangesList).build() + styleBodyRanges.newBuilder().apply { ranges += mentionRanges.ranges }.build() } saveDrafts(it.copy(textDraft = text.toTextDraft(), bodyRangesDraft = bodyRanges?.toDraft())) @@ -148,5 +148,5 @@ private fun String.toTextDraft(): Draft? { } private fun BodyRangeList.toDraft(): Draft { - return Draft(Draft.BODY_RANGES, Base64.encodeBytes(toByteArray())) + return Draft(Draft.BODY_RANGES, Base64.encodeBytes(encode())) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index 30bde47e1e..be01f9695b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -1787,7 +1787,7 @@ class ConversationFragment : return } - if (SignalStore.uiHints().hasNotSeenTextFormattingAlert() && bodyRanges != null && bodyRanges.rangesCount > 0) { + if (SignalStore.uiHints().hasNotSeenTextFormattingAlert() && bodyRanges != null && bodyRanges.ranges.isNotEmpty()) { Dialogs.showFormattedTextDialog(requireContext()) { sendMessage(body, mentions, bodyRanges, messageToEdit, quote, scheduledDate, slideDeck, contacts, clearCompose, linkPreviews, preUploadResults, bypassPreSendSafetyNumberCheck, isViewOnce, afterSendComplete) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/BodyRangeUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/database/BodyRangeUtil.kt index 30fb52667a..7f930bdcb7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/BodyRangeUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/BodyRangeUtil.kt @@ -14,12 +14,12 @@ fun BodyRangeList?.adjustBodyRanges(bodyAdjustments: List): Body return this } - val newBodyRanges = rangesList.toMutableList() + val newBodyRanges = ranges.toMutableList() for (adjustment in bodyAdjustments) { val adjustmentLength = adjustment.oldLength - adjustment.newLength - rangesList.forEachIndexed { listIndex, range -> + ranges.forEachIndexed { listIndex, range -> val needsRangeStartsAfterAdjustment = range.start > adjustment.startIndex val needsRangeCoversAdjustment = range.start <= adjustment.startIndex && range.start + range.length >= adjustment.startIndex + adjustment.oldLength @@ -28,10 +28,10 @@ fun BodyRangeList?.adjustBodyRanges(bodyAdjustments: List): Body val newLength: Int? = if (needsRangeCoversAdjustment) newRange.length - adjustmentLength else null if (newStart != null || newLength != null) { - newBodyRanges[listIndex] = newRange.toBuilder().setStart(newStart ?: newRange.start).setLength(newLength ?: newRange.length).build() + newBodyRanges[listIndex] = newRange.newBuilder().start(newStart ?: newRange.start).length(newLength ?: newRange.length).build() } } } - return BodyRangeList.newBuilder().addAllRanges(newBodyRanges).build() + return BodyRangeList(ranges = newBodyRanges) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt index 3f667f4143..021c1ed4c4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt @@ -35,7 +35,7 @@ import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId import org.whispersystems.signalservice.api.push.ServiceId.ACI -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent +import org.whispersystems.signalservice.internal.push.SyncMessage.CallEvent import java.util.UUID import java.util.concurrent.TimeUnit @@ -1179,9 +1179,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl } @JvmStatic - fun from(type: CallEvent.Type): Type? { + fun from(type: CallEvent.Type?): Type? { return when (type) { - CallEvent.Type.UNKNOWN_TYPE -> null + null, CallEvent.Type.UNKNOWN_TYPE -> null CallEvent.Type.AUDIO_CALL -> AUDIO_CALL CallEvent.Type.VIDEO_CALL -> VIDEO_CALL CallEvent.Type.GROUP_CALL -> GROUP_CALL @@ -1207,9 +1207,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl } @JvmStatic - fun from(direction: CallEvent.Direction): Direction? { + fun from(direction: CallEvent.Direction?): Direction? { return when (direction) { - CallEvent.Direction.UNKNOWN_DIRECTION -> null + null, CallEvent.Direction.UNKNOWN_DIRECTION -> null CallEvent.Direction.INCOMING -> INCOMING CallEvent.Direction.OUTGOING -> OUTGOING } @@ -1284,9 +1284,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl } @JvmStatic - fun from(event: CallEvent.Event): Event? { + fun from(event: CallEvent.Event?): Event? { return when (event) { - CallEvent.Event.UNKNOWN_ACTION -> null + null, CallEvent.Event.UNKNOWN_ACTION -> null CallEvent.Event.ACCEPTED -> ACCEPTED CallEvent.Event.NOT_ACCEPTED -> NOT_ACCEPTED CallEvent.Event.DELETE -> DELETE diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ChatColorsTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ChatColorsTable.kt index afa27e8ad9..829f3581bb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ChatColorsTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ChatColorsTable.kt @@ -70,7 +70,7 @@ class ChatColorsTable(context: Context, databaseHelper: SignalDatabase) : Databa val db: SQLiteDatabase = databaseHelper.signalWritableDatabase val values = ContentValues(1).apply { - put(CHAT_COLORS, chatColors.serialize().toByteArray()) + put(CHAT_COLORS, chatColors.serialize().encode()) } val rowId = db.insert(TABLE_NAME, null, values) @@ -90,7 +90,7 @@ class ChatColorsTable(context: Context, databaseHelper: SignalDatabase) : Databa val db: SQLiteDatabase = databaseHelper.signalWritableDatabase val values = ContentValues(1).apply { - put(CHAT_COLORS, chatColors.serialize().toByteArray()) + put(CHAT_COLORS, chatColors.serialize().encode()) } val rowsUpdated = db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(chatColors.id.longValue)) @@ -131,6 +131,6 @@ class ChatColorsTable(context: Context, databaseHelper: SignalDatabase) : Databa private fun Cursor.getId(): Long = CursorUtil.requireLong(this, ID) private fun Cursor.getChatColors(): ChatColors = ChatColors.forChatColor( ChatColors.Id.forLongValue(getId()), - ChatColor.parseFrom(CursorUtil.requireBlob(this, CHAT_COLORS)) + ChatColor.ADAPTER.decode(CursorUtil.requireBlob(this, CHAT_COLORS)) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt index f7938c1f6a..0ccb08d10c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt @@ -695,8 +695,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT Log.w(TAG, "No group entry. Creating restore placeholder for $groupId") create( groupMasterKey, - DecryptedGroup.newBuilder() - .setRevision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) + DecryptedGroup.Builder() + .revision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) .build(), true ) @@ -765,7 +765,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT values.put(V2_MASTER_KEY, groupMasterKey.serialize()) values.put(V2_REVISION, groupState.revision) - values.put(V2_DECRYPTED_GROUP, groupState.toByteArray()) + values.put(V2_DECRYPTED_GROUP, groupState.encode()) membershipValues.clear() membershipValues.addAll(groupMembers.toContentValues(groupId)) } else { @@ -790,8 +790,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT writableDatabase.endTransaction() } - if (groupState != null && groupState.hasDisappearingMessagesTimer()) { - recipients.setExpireMessages(groupRecipientId, groupState.disappearingMessagesTimer.duration) + if (groupState?.disappearingMessagesTimer != null) { + recipients.setExpireMessages(groupRecipientId, groupState.disappearingMessagesTimer!!.duration) } if (groupId.isMms || Recipient.resolved(groupRecipientId).isProfileSharing) { @@ -849,8 +849,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT writableDatabase.withinTransaction { db -> val record = getGroup(groupIdV1).get() - val newMembers: MutableList = decryptedGroup.membersList.toAciList().toRecipientIds() - val pendingMembers: List = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembersList).toRecipientIds() + val newMembers: MutableList = decryptedGroup.members.toAciList().toRecipientIds() + val pendingMembers: List = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembers).toRecipientIds() newMembers.addAll(pendingMembers) val droppedMembers: List = SetUtil.difference(record.members, newMembers).toList() @@ -895,7 +895,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT val contentValues = ContentValues() contentValues.put(TITLE, title) contentValues.put(V2_REVISION, decryptedGroup.revision) - contentValues.put(V2_DECRYPTED_GROUP, decryptedGroup.toByteArray()) + contentValues.put(V2_DECRYPTED_GROUP, decryptedGroup.encode()) contentValues.put(ACTIVE, if (gv2GroupActive(decryptedGroup)) 1 else 0) if (existingGroup.isPresent && existingGroup.get().unmigratedV1Members.isNotEmpty() && existingGroup.get().isV2Group) { @@ -903,11 +903,11 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT val change = GroupChangeReconstruct.reconstructGroupChange(existingGroup.get().requireV2GroupProperties().decryptedGroup, decryptedGroup) - val addedMembers: Set = change.newMembersList.toAciList().toRecipientIds().toSet() + val addedMembers: Set = change.newMembers.toAciList().toRecipientIds().toSet() val removedMembers: Set = DecryptedGroupUtil.removedMembersServiceIdList(change).toRecipientIds().toSet() - val addedInvites: Set = DecryptedGroupUtil.pendingToServiceIdList(change.newPendingMembersList).toRecipientIds().toSet() + val addedInvites: Set = DecryptedGroupUtil.pendingToServiceIdList(change.newPendingMembers).toRecipientIds().toSet() val removedInvites: Set = DecryptedGroupUtil.removedPendingMembersServiceIdList(change).toRecipientIds().toSet() - val acceptedInvites: Set = change.promotePendingMembersList.toAciList().toRecipientIds().toSet() + val acceptedInvites: Set = change.promotePendingMembers.toAciList().toRecipientIds().toSet() unmigratedV1Members -= addedMembers unmigratedV1Members -= removedMembers @@ -941,8 +941,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT performMembershipUpdate(database, groupId, groupMembers) } - if (decryptedGroup.hasDisappearingMessagesTimer()) { - recipients.setExpireMessages(groupRecipientId, decryptedGroup.disappearingMessagesTimer.duration) + if (decryptedGroup.disappearingMessagesTimer != null) { + recipients.setExpireMessages(groupRecipientId, decryptedGroup.disappearingMessagesTimer!!.duration) } if (groupId.isMms || Recipient.resolved(groupRecipientId).isProfileSharing) { @@ -1192,18 +1192,18 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT class V2GroupProperties(val groupMasterKey: GroupMasterKey, val groupRevision: Int, val decryptedGroupBytes: ByteArray) { val decryptedGroup: DecryptedGroup by lazy { - DecryptedGroup.parseFrom(decryptedGroupBytes) + DecryptedGroup.ADAPTER.decode(decryptedGroupBytes) } val bannedMembers: Set by lazy { - DecryptedGroupUtil.bannedMembersToServiceIdSet(decryptedGroup.bannedMembersList) + DecryptedGroupUtil.bannedMembersToServiceIdSet(decryptedGroup.bannedMembers) } fun isAdmin(recipient: Recipient): Boolean { val aci = recipient.aci return if (aci.isPresent) { - decryptedGroup.membersList.findMemberByAci(aci.get()) + decryptedGroup.members.findMemberByAci(aci.get()) .map { it.role == Member.Role.ADMINISTRATOR } .orElse(false) } else { @@ -1224,7 +1224,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT var memberLevel: Optional = Optional.empty() if (serviceId is ACI) { - memberLevel = decryptedGroup.membersList.findMemberByAci(serviceId) + memberLevel = decryptedGroup.members.findMemberByAci(serviceId) .map { member -> if (member.role == Member.Role.ADMINISTRATOR) { MemberLevel.ADMINISTRATOR @@ -1235,12 +1235,12 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT } if (memberLevel.isAbsent()) { - memberLevel = decryptedGroup.pendingMembersList.findPendingByServiceId(serviceId) + memberLevel = decryptedGroup.pendingMembers.findPendingByServiceId(serviceId) .map { MemberLevel.PENDING_MEMBER } } if (memberLevel.isAbsent() && serviceId is ACI) { - memberLevel = decryptedGroup.requestingMembersList.findRequestingByAci(serviceId) + memberLevel = decryptedGroup.requestingMembers.findRequestingByAci(serviceId) .map { _ -> MemberLevel.REQUESTING_MEMBER } } @@ -1258,12 +1258,12 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT fun getMemberRecipientIds(memberSet: MemberSet): List { val includeSelf = memberSet.includeSelf val selfAci = SignalStore.account().requireAci() - val recipients: MutableList = ArrayList(decryptedGroup.membersCount + decryptedGroup.pendingMembersCount) + val recipients: MutableList = ArrayList(decryptedGroup.members.size + decryptedGroup.pendingMembers.size) var unknownMembers = 0 var unknownPending = 0 - for (aci in decryptedGroup.membersList.toAciListWithUnknowns()) { + for (aci in decryptedGroup.members.toAciListWithUnknowns()) { if (aci.isUnknown) { unknownMembers++ } else if (includeSelf || selfAci != aci) { @@ -1272,7 +1272,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT } if (memberSet.includePending) { - for (serviceId in DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembersList)) { + for (serviceId in DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembers)) { if (serviceId.isUnknown) { unknownPending++ } else if (includeSelf || selfAci != serviceId) { @@ -1290,7 +1290,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT fun getMemberServiceIds(): List { return decryptedGroup - .membersList + .members .asSequence() .map { ACI.parseOrNull(it.aciBytes) } .filterNotNull() @@ -1368,8 +1368,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT private fun gv2GroupActive(decryptedGroup: DecryptedGroup): Boolean { val aci = SignalStore.account().requireAci() - return decryptedGroup.membersList.findMemberByAci(aci).isPresent || - DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembersList, aci).isPresent + return decryptedGroup.members.findMemberByAci(aci).isPresent || + DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembers, aci).isPresent } private fun List.toRecipientIds(): MutableList { @@ -1412,7 +1412,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT } private fun getV2GroupMembers(decryptedGroup: DecryptedGroup, shouldRetry: Boolean): List { - val ids: List = decryptedGroup.membersList.toAciList().toRecipientIds() + val ids: List = decryptedGroup.members.toAciList().toRecipientIds() return if (RemappedRecords.getInstance().areAnyRemapped(ids)) { if (shouldRetry) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java index 002275d85b..c6f2bf3021 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; +import java.util.stream.Collectors; public final class MentionUtil { @@ -93,26 +94,29 @@ public final class MentionUtil { return null; } - BodyRangeList.Builder builder = BodyRangeList.newBuilder(); - - for (Mention mention : mentions) { - String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString(); - builder.addRanges(BodyRangeList.BodyRange.newBuilder() - .setMentionUuid(uuid) - .setStart(mention.getStart()) - .setLength(mention.getLength())); - } - + BodyRangeList.Builder builder = new BodyRangeList.Builder(); + builder.ranges( + mentions.stream() + .map(mention -> { + String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString(); + return new BodyRangeList.BodyRange.Builder() + .mentionUuid(uuid) + .start(mention.getStart()) + .length(mention.getLength()) + .build(); + }) + .collect(Collectors.toList()) + ); return builder.build(); } public static @NonNull List bodyRangeListToMentions(@Nullable BodyRangeList bodyRanges) { if (bodyRanges != null) { - return Stream.of(bodyRanges.getRangesList()) - .filter(bodyRange -> bodyRange.getAssociatedValueCase() == BodyRangeList.BodyRange.AssociatedValueCase.MENTIONUUID) + return Stream.of(bodyRanges.ranges) + .filter(bodyRange -> bodyRange.mentionUuid != null) .map(mention -> { - RecipientId id = Recipient.externalPush(ServiceId.parseOrThrow(mention.getMentionUuid())).getId(); - return new Mention(id, mention.getStart(), mention.getLength()); + RecipientId id = Recipient.externalPush(ServiceId.parseOrThrow(mention.mentionUuid)).getId(); + return new Mention(id, mention.start, mention.length); }) .toList(); } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageSendLogTables.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageSendLogTables.kt index e93d08b530..16e3d7096f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageSendLogTables.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageSendLogTables.kt @@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.RecipientAccessList import org.whispersystems.signalservice.api.crypto.ContentHint import org.whispersystems.signalservice.api.messages.SendMessageResult -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.Content /** * Stores a rolling buffer of all outgoing messages. Used for the retry logic required for sender key. @@ -191,7 +191,7 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal return -1 } - val content: SignalServiceProtos.Content = results.first { it.isSuccess && it.success.content.isPresent }.success.content.get() + val content: Content = results.first { it.isSuccess && it.success.content.isPresent }.success.content.get() return insert(recipientDevices, sentTimestamp, content, contentHint, listOf(messageId), urgent) } @@ -228,14 +228,14 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal return payloadId } - private fun insert(recipients: List, dateSent: Long, content: SignalServiceProtos.Content, contentHint: ContentHint, messageIds: List, urgent: Boolean): Long { + private fun insert(recipients: List, dateSent: Long, content: Content, contentHint: ContentHint, messageIds: List, urgent: Boolean): Long { val db = databaseHelper.signalWritableDatabase db.beginTransaction() try { val payloadValues = ContentValues().apply { put(MslPayloadTable.DATE_SENT, dateSent) - put(MslPayloadTable.CONTENT, content.toByteArray()) + put(MslPayloadTable.CONTENT, content.encode()) put(MslPayloadTable.CONTENT_HINT, contentHint.type) put(MslPayloadTable.URGENT, urgent.toInt()) } @@ -300,7 +300,7 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal return MessageLogEntry( recipientId = RecipientId.from(CursorUtil.requireLong(entryCursor, MslRecipientTable.RECIPIENT_ID)), dateSent = CursorUtil.requireLong(entryCursor, MslPayloadTable.DATE_SENT), - content = SignalServiceProtos.Content.parseFrom(CursorUtil.requireBlob(entryCursor, MslPayloadTable.CONTENT)), + content = Content.ADAPTER.decode(CursorUtil.requireBlob(entryCursor, MslPayloadTable.CONTENT)), contentHint = ContentHint.fromType(CursorUtil.requireInt(entryCursor, MslPayloadTable.CONTENT_HINT)), urgent = entryCursor.requireBoolean(MslPayloadTable.URGENT), relatedMessages = messageIds diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt index 5202a076a5..526ba7993e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -25,7 +25,6 @@ import androidx.annotation.VisibleForTesting import androidx.core.content.contentValuesOf import com.google.android.mms.pdu_alt.NotificationInd import com.google.android.mms.pdu_alt.PduHeaders -import com.google.protobuf.InvalidProtocolBufferException import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -142,7 +141,7 @@ import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.isStory import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage import org.whispersystems.signalservice.api.push.ServiceId -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage +import org.whispersystems.signalservice.internal.push.SyncMessage import java.io.Closeable import java.io.IOException import java.util.LinkedList @@ -523,8 +522,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val bodyRanges: BodyRangeList? = if (data != null) { try { - BodyRangeList.parseFrom(data) - } catch (e: InvalidProtocolBufferException) { + BodyRangeList.ADAPTER.decode(data) + } catch (e: IOException) { Log.w(TAG, "Unable to parse quote body ranges", e) null } @@ -541,12 +540,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat if (data != null) { try { val bodyRanges = BodyRangeList - .parseFrom(data) - .rangesList - .filter { bodyRange -> bodyRange.associatedValueCase != BodyRangeList.BodyRange.AssociatedValueCase.MENTIONUUID } + .ADAPTER.decode(data) + .ranges + .filter { bodyRange -> bodyRange.mentionUuid == null } - return BodyRangeList.newBuilder().addAllRanges(bodyRanges).build() - } catch (e: InvalidProtocolBufferException) { + return BodyRangeList(ranges = bodyRanges) + } catch (e: IOException) { Log.w(TAG, "Unable to parse quote body ranges", e) } } @@ -847,14 +846,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val messageId: MessageId = writableDatabase.withinTransaction { db -> val self = Recipient.self() val markRead = joinedUuids.contains(self.requireServiceId().rawUuid) || self.id == sender - val updateDetails: ByteArray = GroupCallUpdateDetails.newBuilder() - .setEraId(eraId) - .setStartedCallUuid(Recipient.resolved(sender).requireServiceId().toString()) - .setStartedCallTimestamp(timestamp) - .addAllInCallUuids(joinedUuids.map { it.toString() }) - .setIsCallFull(isCallFull) - .build() - .toByteArray() + val updateDetails: ByteArray = GroupCallUpdateDetails( + eraId = eraId, + startedCallUuid = Recipient.resolved(sender).requireServiceId().toString(), + startedCallTimestamp = timestamp, + inCallUuids = joinedUuids.map { it.toString() }, + isCallFull = isCallFull + ).encode() val values = contentValuesOf( FROM_RECIPIENT_ID to sender.serialize(), @@ -893,7 +891,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val updateDetail = GroupCallUpdateDetailsUtil.parse(message.body) val contentValues = contentValuesOf( - BODY to Base64.encodeBytes(updateDetail.toBuilder().setStartedCallTimestamp(timestamp).build().toByteArray()), + BODY to Base64.encodeBytes(updateDetail.newBuilder().startedCallTimestamp(timestamp).build().encode()), DATE_SENT to timestamp, DATE_RECEIVED to timestamp ) @@ -1157,14 +1155,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun insertProfileNameChangeMessages(recipient: Recipient, newProfileName: String, previousProfileName: String) { writableDatabase.withinTransaction { db -> val groupRecords = groups.getGroupsContainingMember(recipient.id, false) - val profileChangeDetails = ProfileChangeDetails.newBuilder() - .setProfileNameChange( - ProfileChangeDetails.StringChange.newBuilder() - .setNew(newProfileName) - .setPrevious(previousProfileName) - ) - .build() - .toByteArray() + val profileChangeDetails = ProfileChangeDetails(profileNameChange = ProfileChangeDetails.StringChange(previous = previousProfileName, newValue = newProfileName)) + .encode() val threadIdsToUpdate = mutableListOf().apply { add(threads.getThreadIdFor(recipient.id)) @@ -1294,7 +1286,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat READ to 1, TYPE to MessageTypes.THREAD_MERGE_TYPE, THREAD_ID to threadId, - BODY to Base64.encodeBytes(event.toByteArray()) + BODY to Base64.encodeBytes(event.encode()) ) .run() ApplicationDependencies.getDatabaseObserver().notifyConversationListeners(threadId) @@ -1313,7 +1305,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat READ to 1, TYPE to MessageTypes.SESSION_SWITCHOVER_TYPE, THREAD_ID to threadId, - BODY to Base64.encodeBytes(event.toByteArray()) + BODY to Base64.encodeBytes(event.encode()) ) .run() ApplicationDependencies.getDatabaseObserver().notifyConversationListeners(threadId) @@ -2554,15 +2546,15 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ) } else { val giftBadge: GiftBadge? = if (body != null && MessageTypes.isGiftBadge(outboxType)) { - GiftBadge.parseFrom(Base64.decode(body)) + GiftBadge.ADAPTER.decode(Base64.decode(body)) } else { null } val messageRanges: BodyRangeList? = if (messageRangesData != null) { try { - BodyRangeList.parseFrom(messageRangesData) - } catch (e: InvalidProtocolBufferException) { + BodyRangeList.ADAPTER.decode(messageRangesData) + } catch (e: IOException) { Log.w(TAG, "Error parsing message ranges", e) null } @@ -2648,15 +2640,15 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat contentValues.put(QUOTE_TYPE, retrieved.quote.type.code) contentValues.put(QUOTE_MISSING, if (retrieved.quote.isOriginalMissing) 1 else 0) - val quoteBodyRanges: BodyRangeList.Builder = retrieved.quote.bodyRanges?.toBuilder() ?: BodyRangeList.newBuilder() + val quoteBodyRanges: BodyRangeList.Builder = retrieved.quote.bodyRanges?.newBuilder() ?: BodyRangeList.Builder() val mentionsList = MentionUtil.mentionsToBodyRangeList(retrieved.quote.mentions) if (mentionsList != null) { - quoteBodyRanges.addAllRanges(mentionsList.rangesList) + quoteBodyRanges.ranges += mentionsList.ranges } - if (quoteBodyRanges.rangesCount > 0) { - contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().toByteArray()) + if (quoteBodyRanges.ranges.isNotEmpty()) { + contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().encode()) } quoteAttachments += retrieved.quote.attachments @@ -2925,12 +2917,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .run() .use { cursor -> if (cursor.moveToFirst()) { - val giftBadge = GiftBadge.parseFrom(Base64.decode(cursor.requireNonNullString(BODY))) - val updatedBadge = giftBadge.toBuilder().setRedemptionState(redemptionState).build() + val giftBadge = GiftBadge.ADAPTER.decode(Base64.decode(cursor.requireNonNullString(BODY))) + val updatedBadge = giftBadge.newBuilder().redemptionState(redemptionState).build() updated = db .update(TABLE_NAME) - .values(BODY to Base64.encodeBytes(updatedBadge.toByteArray())) + .values(BODY to Base64.encodeBytes(updatedBadge.encode())) .where("$ID = ?", messageId) .run() > 0 @@ -3113,18 +3105,18 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val adjustedQuoteBodyRanges = message.outgoingQuote.bodyRanges.adjustBodyRanges(updated.bodyAdjustments) val quoteBodyRanges: BodyRangeList.Builder = if (adjustedQuoteBodyRanges != null) { - adjustedQuoteBodyRanges.toBuilder() + adjustedQuoteBodyRanges.newBuilder() } else { - BodyRangeList.newBuilder() + BodyRangeList.Builder() } val mentionsList = MentionUtil.mentionsToBodyRangeList(updated.mentions) if (mentionsList != null) { - quoteBodyRanges.addAllRanges(mentionsList.rangesList) + quoteBodyRanges.ranges += mentionsList.ranges } - if (quoteBodyRanges.rangesCount > 0) { - contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().toByteArray()) + if (quoteBodyRanges.ranges.isNotEmpty()) { + contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().encode()) } if (editedMessage == null) { @@ -3252,7 +3244,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat contentValues.put(BODY, body) contentValues.put(MENTIONS_SELF, if (mentionsSelf) 1 else 0) if (messageRanges != null) { - contentValues.put(MESSAGE_RANGES, messageRanges.toByteArray()) + contentValues.put(MESSAGE_RANGES, messageRanges.encode()) } val (messageId, insertedAttachments) = writableDatabase.withinTransaction { db -> @@ -4294,12 +4286,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val bytes: ByteArray? = cursor.requireBlob(EXPORT_STATE) if (bytes == null) { - MessageExportState.getDefaultInstance() + MessageExportState() } else { try { - MessageExportState.parseFrom(bytes) - } catch (e: InvalidProtocolBufferException) { - MessageExportState.getDefaultInstance() + MessageExportState.ADAPTER.decode(bytes) + } catch (e: IOException) { + MessageExportState() } } } ?: throw NoSuchMessageException("The requested message does not exist.") @@ -4333,7 +4325,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat private fun setMessageExportState(messageId: MessageId, messageExportState: MessageExportState) { writableDatabase .update(TABLE_NAME) - .values(EXPORT_STATE to messageExportState.toByteArray()) + .values(EXPORT_STATE to messageExportState.encode()) .where("$ID = ?", messageId.id) .run() } @@ -4573,7 +4565,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } fun setTimestampReadFromSyncMessageProto(readMessages: List, proposedExpireStarted: Long, threadToLatestRead: MutableMap): Collection { - val reads: List = readMessages.map { r -> ReadMessage(ServiceId.parseOrThrow(r.senderAci), r.timestamp) } + val reads: List = readMessages.map { r -> ReadMessage(ServiceId.parseOrThrow(r.senderAci!!), r.timestamp!!) } return setTimestampReadFromSyncMessage(reads, proposedExpireStarted, threadToLatestRead) } @@ -4920,8 +4912,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat if (data != null) { try { - bodyRanges[CursorUtil.requireLong(cursor, ID)] = BodyRangeList.parseFrom(data) - } catch (e: InvalidProtocolBufferException) { + bodyRanges[CursorUtil.requireLong(cursor, ID)] = BodyRangeList.ADAPTER.decode(data) + } catch (e: IOException) { Log.w(TAG, "Unable to parse body ranges for search", e) } } @@ -5136,11 +5128,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } override fun getMessageExportStateForCurrentRecord(): MessageExportState { - val messageExportState = CursorUtil.requireBlob(cursor, EXPORT_STATE) ?: return MessageExportState.getDefaultInstance() + val messageExportState = CursorUtil.requireBlob(cursor, EXPORT_STATE) ?: return MessageExportState() return try { - MessageExportState.parseFrom(messageExportState) - } catch (e: InvalidProtocolBufferException) { - MessageExportState.getDefaultInstance() + MessageExportState.ADAPTER.decode(messageExportState) + } catch (e: IOException) { + MessageExportState() } } @@ -5192,7 +5184,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val slideDeck = SlideDeck(MmsNotificationAttachment(status, messageSize)) val giftBadge: GiftBadge? = if (body != null && MessageTypes.isGiftBadge(mailbox)) { try { - GiftBadge.parseFrom(Base64.decode(body)) + GiftBadge.ADAPTER.decode(Base64.decode(body)) } catch (e: IOException) { Log.w(TAG, "Error parsing gift badge", e) null @@ -5286,8 +5278,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val messageRanges: BodyRangeList? = if (messageRangesData != null) { try { - BodyRangeList.parseFrom(messageRangesData) - } catch (e: InvalidProtocolBufferException) { + BodyRangeList.ADAPTER.decode(messageRangesData) + } catch (e: IOException) { Log.w(TAG, "Error parsing message ranges", e) null } @@ -5297,7 +5289,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val giftBadge: GiftBadge? = if (body != null && MessageTypes.isGiftBadge(box)) { try { - GiftBadge.parseFrom(Base64.decode(body)) + GiftBadge.ADAPTER.decode(Base64.decode(body)) } catch (e: IOException) { Log.w(TAG, "Error parsing gift badge", e) null diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtil.java index 5cf93cab71..4d577788b5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtil.java @@ -4,8 +4,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.annimon.stream.Stream; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; import com.mobilecoin.lib.KeyImage; import com.mobilecoin.lib.Receipt; import com.mobilecoin.lib.RistrettoPublic; @@ -14,40 +12,44 @@ import com.mobilecoin.lib.exceptions.SerializationException; import org.thoughtcrime.securesms.payments.proto.PaymentMetaData; +import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Set; +import okio.ByteString; + public final class PaymentMetaDataUtil { public static PaymentMetaData parseOrThrow(byte[] requireBlob) { try { - return PaymentMetaData.parseFrom(requireBlob); - } catch (InvalidProtocolBufferException e) { + return PaymentMetaData.ADAPTER.decode(requireBlob); + } catch (IOException e) { throw new IllegalStateException(e); } } public static @NonNull PaymentMetaData fromReceipt(@Nullable byte[] receipt) throws SerializationException { - PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder(); + PaymentMetaData.MobileCoinTxoIdentification.Builder builder = new PaymentMetaData.MobileCoinTxoIdentification.Builder(); if (receipt != null) { addReceiptData(receipt, builder); } - return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build(); + return new PaymentMetaData.Builder().mobileCoinTxoIdentification(builder.build()).build(); } public static @NonNull PaymentMetaData fromKeysAndImages(@NonNull List publicKeys, @NonNull List keyImages) { - PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder(); + PaymentMetaData.MobileCoinTxoIdentification.Builder builder = new PaymentMetaData.MobileCoinTxoIdentification.Builder(); - builder.addAllKeyImages(keyImages); - builder.addAllPublicKey(publicKeys); + builder.keyImages(keyImages); + builder.publicKey(publicKeys); - return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build(); + return new PaymentMetaData.Builder().mobileCoinTxoIdentification(builder.build()).build(); } public static @NonNull PaymentMetaData fromReceiptAndTransaction(@Nullable byte[] receipt, @Nullable byte[] transaction) throws SerializationException { - PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder(); + PaymentMetaData.MobileCoinTxoIdentification.Builder builder = new PaymentMetaData.MobileCoinTxoIdentification.Builder(); if (transaction != null) { addTransactionData(transaction, builder); @@ -55,7 +57,7 @@ public final class PaymentMetaDataUtil { addReceiptData(receipt, builder); } - return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build(); + return new PaymentMetaData.Builder().mobileCoinTxoIdentification(builder.build()).build(); } private static void addReceiptData(@NonNull byte[] receipt, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) throws SerializationException { @@ -66,19 +68,25 @@ public final class PaymentMetaDataUtil { private static void addTransactionData(@NonNull byte[] transactionBytes, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) throws SerializationException { Transaction transaction = Transaction.fromBytes(transactionBytes); Set keyImages = transaction.getKeyImages(); + + List newKeyImages = new ArrayList<>(builder.keyImages); for (KeyImage keyImage : keyImages) { - builder.addKeyImages(ByteString.copyFrom(keyImage.getData())); + newKeyImages.add(ByteString.of(keyImage.getData())); } + builder.keyImages(newKeyImages); + for (RistrettoPublic publicKey : transaction.getOutputPublicKeys()) { addPublicKey(builder, publicKey); } } private static void addPublicKey(@NonNull PaymentMetaData.MobileCoinTxoIdentification.Builder builder, @NonNull RistrettoPublic publicKey) { - builder.addPublicKey(ByteString.copyFrom(publicKey.getKeyBytes())); + List publicKeys = new ArrayList<>(builder.publicKey); + publicKeys.add(ByteString.of(publicKey.getKeyBytes())); + builder.publicKey(publicKeys); } public static byte[] receiptPublic(@NonNull PaymentMetaData paymentMetaData) { - return Stream.of(paymentMetaData.getMobileCoinTxoIdentification().getPublicKeyList()).single().toByteArray(); + return Stream.of(paymentMetaData.mobileCoinTxoIdentification.publicKey).single().toByteArray(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/PaymentTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/PaymentTable.java index 77494fa7aa..a6590a9cc7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/PaymentTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/PaymentTable.java @@ -11,11 +11,12 @@ import androidx.annotation.WorkerThread; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import com.google.protobuf.InvalidProtocolBufferException; import com.mobilecoin.lib.exceptions.SerializationException; import org.signal.core.util.CursorExtensionsKt; +import org.signal.core.util.CursorUtil; import org.signal.core.util.SQLiteDatabaseExtensionsKt; +import org.signal.core.util.SqlUtil; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord; import org.thoughtcrime.securesms.database.model.MessageId; @@ -32,12 +33,11 @@ import org.thoughtcrime.securesms.payments.State; import org.thoughtcrime.securesms.payments.proto.PaymentMetaData; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.Base64; -import org.signal.core.util.CursorUtil; -import org.signal.core.util.SqlUtil; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.whispersystems.signalservice.api.payments.Money; import org.whispersystems.signalservice.api.util.UuidUtil; +import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -230,8 +230,8 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData values.put(NOTE, note); values.put(DIRECTION, direction.serialize()); values.put(STATE, state.serialize()); - values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).toByteArray()); - values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).toByteArray()); + values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).encode()); + values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).encode()); if (transaction != null) { values.put(TRANSACTION, transaction); } else { @@ -245,9 +245,9 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData values.putNull(PUBLIC_KEY); } if (metaData != null) { - values.put(META_DATA, metaData.toByteArray()); + values.put(META_DATA, metaData.encode()); } else { - values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).toByteArray()); + values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).encode()); } values.put(SEEN, seen ? 1 : 0); @@ -469,11 +469,11 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData values.put(RECEIPT, receipt); try { values.put(PUBLIC_KEY, Base64.encodeBytes(PaymentMetaDataUtil.receiptPublic(PaymentMetaDataUtil.fromReceipt(receipt)))); - values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).toByteArray()); + values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).encode()); } catch (SerializationException e) { throw new IllegalArgumentException(e); } - values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).toByteArray()); + values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).encode()); database.beginTransaction(); try { @@ -526,7 +526,7 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData values.put(STATE, state.serialize()); if (amount != null) { - values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).toByteArray()); + values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).encode()); } if (state == State.FAILED) { @@ -623,9 +623,9 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData private static @NonNull Money getMoneyValue(@NonNull byte[] blob) { try { - CryptoValue cryptoValue = CryptoValue.parseFrom(blob); + CryptoValue cryptoValue = CryptoValue.ADAPTER.decode(blob); return CryptoValueUtil.cryptoValueToMoney(cryptoValue); - } catch (InvalidProtocolBufferException e) { + } catch (IOException e) { throw new AssertionError(e); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt index 38069f5f04..e4adb498a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -9,8 +9,7 @@ import android.text.TextUtils import androidx.annotation.VisibleForTesting import androidx.core.content.contentValuesOf import app.cash.exhaustive.Exhaustive -import com.google.protobuf.ByteString -import com.google.protobuf.InvalidProtocolBufferException +import okio.ByteString.Companion.toByteString import org.signal.core.util.Bitmask import org.signal.core.util.CursorUtil import org.signal.core.util.SqlUtil @@ -814,7 +813,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } updateExtras(recipientId) { - it.setHideStory(insert.shouldHideStory()) + it.hideStory(insert.shouldHideStory()) } threadDatabase.applyStorageSyncUpdate(recipientId, insert) @@ -871,7 +870,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } updateExtras(recipientId) { - it.setHideStory(update.new.shouldHideStory()) + it.hideStory(update.new.shouldHideStory()) } threads.applyStorageSyncUpdate(recipientId, update.new) @@ -910,8 +909,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da Log.i(TAG, "Creating restore placeholder for $groupId") val createdId = groups.create( masterKey, - DecryptedGroup.newBuilder() - .setRevision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) + DecryptedGroup.Builder() + .revision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) .build() ) @@ -921,7 +920,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da groups.setShowAsStoryState(groupId, insert.storySendMode.toShowAsStoryState()) updateExtras(recipient.id) { - it.setHideStory(insert.shouldHideStory()) + it.hideStory(insert.shouldHideStory()) } Log.i(TAG, "Scheduling request for latest group info for $groupId") @@ -943,7 +942,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val recipient = Recipient.externalGroupExact(groupId) updateExtras(recipient.id) { - it.setHideStory(update.new.shouldHideStory()) + it.hideStory(update.new.shouldHideStory()) } groups.setShowAsStoryState(groupId, update.new.storySendMode.toShowAsStoryState()) @@ -1222,7 +1221,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da Log.d(TAG, "No recipients utilizing updated chat color.") } else { val values = ContentValues(2).apply { - put(CHAT_COLORS, chatColors.serialize().toByteArray()) + put(CHAT_COLORS, chatColors.serialize().encode()) put(CUSTOM_CHAT_COLORS_ID, chatColors.id.longValue) } @@ -1313,7 +1312,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da fun setColor(id: RecipientId, color: ChatColors) { val values = ContentValues().apply { - put(CHAT_COLORS, color.serialize().toByteArray()) + put(CHAT_COLORS, color.serialize().encode()) put(CUSTOM_CHAT_COLORS_ID, color.id.longValue) } if (update(id, values)) { @@ -1427,7 +1426,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da fun setLastSessionResetTime(id: RecipientId, lastResetTime: DeviceLastResetTime) { val values = ContentValues(1).apply { - put(LAST_SESSION_RESET, lastResetTime.toByteArray()) + put(LAST_SESSION_RESET, lastResetTime.encode()) } update(id, values) } @@ -1438,28 +1437,25 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return try { val serialized = cursor.requireBlob(LAST_SESSION_RESET) if (serialized != null) { - DeviceLastResetTime.parseFrom(serialized) + DeviceLastResetTime.ADAPTER.decode(serialized) } else { - DeviceLastResetTime.newBuilder().build() + DeviceLastResetTime() } - } catch (e: InvalidProtocolBufferException) { + } catch (e: IOException) { Log.w(TAG, e) - DeviceLastResetTime.newBuilder().build() + DeviceLastResetTime() } } } - return DeviceLastResetTime.newBuilder().build() + return DeviceLastResetTime() } fun setBadges(id: RecipientId, badges: List) { - val badgeListBuilder = BadgeList.newBuilder() - for (badge in badges) { - badgeListBuilder.addBadges(toDatabaseBadge(badge)) - } + val badgeList = BadgeList(badges = badges.map { toDatabaseBadge(it) }) val values = ContentValues(1).apply { - put(BADGES, badgeListBuilder.build().toByteArray()) + put(BADGES, badgeList.encode()) } if (update(id, values)) { @@ -1568,12 +1564,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ): Boolean { val selection = "$ID = ? AND $PROFILE_KEY = ?" val args = arrayOf(id.serialize(), Base64.encodeBytes(profileKey.serialize())) - val columnData = ExpiringProfileKeyCredentialColumnData.newBuilder() - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setExpiringProfileKeyCredential(ByteString.copyFrom(expiringProfileKeyCredential.serialize())) + val columnData = ExpiringProfileKeyCredentialColumnData.Builder() + .profileKey(profileKey.serialize().toByteString()) + .expiringProfileKeyCredential(expiringProfileKeyCredential.serialize().toByteString()) .build() val values = ContentValues(1).apply { - put(EXPIRING_PROFILE_KEY_CREDENTIAL, Base64.encodeBytes(columnData.toByteArray())) + put(EXPIRING_PROFILE_KEY_CREDENTIAL, Base64.encodeBytes(columnData.encode())) } val updateQuery = SqlUtil.buildTrueUpdateQuery(selection, args, values) @@ -1850,9 +1846,9 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da private fun setWallpaper(id: RecipientId, wallpaper: Wallpaper?) { val existingWallpaperUri = getWallpaperUri(id) val values = ContentValues().apply { - put(WALLPAPER, wallpaper?.toByteArray()) - if (wallpaper != null && wallpaper.hasFile()) { - put(WALLPAPER_URI, wallpaper.file.uri) + put(WALLPAPER, wallpaper?.encode()) + if (wallpaper?.file_ != null) { + put(WALLPAPER_URI, wallpaper.file_.uri) } else { putNull(WALLPAPER_URI) } @@ -1869,8 +1865,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da fun setDimWallpaperInDarkTheme(id: RecipientId, enabled: Boolean) { val wallpaper = getWallpaper(id) ?: throw IllegalStateException("No wallpaper set for $id") - val updated = wallpaper.toBuilder() - .setDimLevelInDarkTheme(if (enabled) ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME else 0f) + val updated = wallpaper.newBuilder() + .dimLevelInDarkTheme(if (enabled) ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME else 0f) .build() setWallpaper(id, updated) @@ -1882,8 +1878,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val raw = cursor.requireBlob(WALLPAPER) return if (raw != null) { try { - Wallpaper.parseFrom(raw) - } catch (e: InvalidProtocolBufferException) { + Wallpaper.ADAPTER.decode(raw) + } catch (e: IOException) { null } } else { @@ -1898,8 +1894,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da private fun getWallpaperUri(id: RecipientId): Uri? { val wallpaper = getWallpaper(id) - return if (wallpaper != null && wallpaper.hasFile()) { - Uri.parse(wallpaper.file.uri) + return if (wallpaper != null && wallpaper.file_ != null) { + Uri.parse(wallpaper.file_.uri) } else { null } @@ -2046,13 +2042,13 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } fun setHideStory(id: RecipientId, hideStory: Boolean) { - updateExtras(id) { it.setHideStory(hideStory) } + updateExtras(id) { it.hideStory(hideStory) } rotateStorageId(id) StorageSyncHelper.scheduleSyncForDataChange() } fun updateLastStoryViewTimestamp(id: RecipientId) { - updateExtras(id) { it.setLastStoryView(System.currentTimeMillis()) } + updateExtras(id) { it.lastStoryView(System.currentTimeMillis()) } } fun clearUsernameIfExists(username: String) { @@ -2329,10 +2325,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da is PnpOperation.SetPni -> { affectedIds.add(operation.recipientId) } + is PnpOperation.Merge -> { oldIds.add(operation.secondaryId) affectedIds.add(operation.primaryId) } + is PnpOperation.SessionSwitchoverInsert -> {} is PnpOperation.ChangeNumberInsert -> changedNumberId = operation.recipientId } @@ -2364,6 +2362,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .where("$ID = ?", operation.recipientId) .run() } + is PnpOperation.RemovePni -> { writableDatabase .update(TABLE_NAME) @@ -2371,6 +2370,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .where("$ID = ?", operation.recipientId) .run() } + is PnpOperation.SetAci -> { writableDatabase .update(TABLE_NAME) @@ -2382,6 +2382,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .where("$ID = ?", operation.recipientId) .run() } + is PnpOperation.SetE164 -> { writableDatabase .update(TABLE_NAME) @@ -2389,6 +2390,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .where("$ID = ?", operation.recipientId) .run() } + is PnpOperation.SetPni -> { writableDatabase .update(TABLE_NAME) @@ -2406,20 +2408,19 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .where("$ID = ?", operation.recipientId) .run() } + is PnpOperation.Merge -> { val mergeResult: MergeResult = merge(operation.primaryId, operation.secondaryId, inputPni) hadThreadMerge = hadThreadMerge || mergeResult.neededThreadMerge } + is PnpOperation.SessionSwitchoverInsert -> { if (hadThreadMerge) { Log.d(TAG, "Skipping SSE insert because we already had a thread merge event.") } else { val threadId: Long? = threads.getThreadIdFor(operation.recipientId) if (threadId != null) { - val event = SessionSwitchoverEvent - .newBuilder() - .setE164(operation.e164 ?: "") - .build() + val event = SessionSwitchoverEvent(e164 = operation.e164 ?: "") try { SignalDatabase.messages.insertSessionSwitchoverEvent(operation.recipientId, threadId, event) } catch (e: Exception) { @@ -2471,6 +2472,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } } + is PnpOperation.ChangeNumberInsert -> { if (changeSet.id is PnpIdResolver.PnpNoopId) { SignalDatabase.messages.insertNumberChangeMessages(changeSet.id.recipientId) @@ -2485,6 +2487,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da is PnpIdResolver.PnpNoopId -> { changeSet.id.recipientId } + is PnpIdResolver.PnpInsert -> { val id: Long = writableDatabase.insert(TABLE_NAME, null, buildContentValuesForNewUser(changeSet.id.e164, changeSet.id.pni, changeSet.id.aci)) RecipientId.from(id) @@ -3094,8 +3097,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val serializedChatColors = cursor.requireBlob(CHAT_COLORS) var chatColors: ChatColors? = if (serializedChatColors != null) { try { - forChatColor(forLongValue(customChatColorsId), ChatColor.parseFrom(serializedChatColors)) - } catch (e: InvalidProtocolBufferException) { + forChatColor(forLongValue(customChatColorsId), ChatColor.ADAPTER.decode(serializedChatColors)) + } catch (e: IOException) { null } } else { @@ -3117,7 +3120,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } val contentValues = ContentValues().apply { - put(CHAT_COLORS, chatColors.serialize().toByteArray()) + put(CHAT_COLORS, chatColors.serialize().encode()) put(CUSTOM_CHAT_COLORS_ID, chatColors.id.longValue) } db.update(TABLE_NAME, contentValues, "$ID = ?", arrayOf(id.toString())) @@ -3604,7 +3607,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } fun manuallyShowAvatar(recipientId: RecipientId) { - updateExtras(recipientId) { b: RecipientExtras.Builder -> b.setManuallyShownAvatar(true) } + updateExtras(recipientId) { b: RecipientExtras.Builder -> b.manuallyShownAvatar(true) } } fun getCapabilities(id: RecipientId): RecipientRecord.Capabilities? { @@ -3629,8 +3632,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da db.query(TABLE_NAME, arrayOf(ID, EXTRAS), ID_WHERE, SqlUtil.buildArgs(recipientId), null, null, null).use { cursor -> if (cursor.moveToNext()) { val state = getRecipientExtras(cursor) - val builder = if (state != null) state.toBuilder() else RecipientExtras.newBuilder() - val updatedState = updater.apply(builder).build().toByteArray() + val builder = state?.newBuilder() ?: RecipientExtras.Builder() + val updatedState = updater.apply(builder).build().encode() val values = ContentValues(1).apply { put(EXTRAS, updatedState) } @@ -3782,7 +3785,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da // Thread Merge Event (remaps happen inside ThreadTable#merge) if (threadMerge.neededMerge) { - val mergeEvent: ThreadMergeEvent.Builder = ThreadMergeEvent.newBuilder() + val mergeEvent: ThreadMergeEvent.Builder = ThreadMergeEvent.Builder() if (secondaryRecord.e164 != null) { mergeEvent.previousE164 = secondaryRecord.e164 @@ -3807,7 +3810,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da CALL_VIBRATE to if (primaryRecord.callVibrateState != VibrateState.DEFAULT) primaryRecord.callVibrateState.id else secondaryRecord.callVibrateState.id, NOTIFICATION_CHANNEL to (primaryRecord.notificationChannel ?: secondaryRecord.notificationChannel), MUTE_UNTIL to if (primaryRecord.muteUntil > 0) primaryRecord.muteUntil else secondaryRecord.muteUntil, - CHAT_COLORS to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.serialize().toByteArray() }.orElse(null), + CHAT_COLORS to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.serialize().encode() }.orElse(null), AVATAR_COLOR to primaryRecord.avatarColor.serialize(), CUSTOM_CHAT_COLORS_ID to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.id.longValue }.orElse(null), MESSAGE_EXPIRATION_TIME to if (primaryRecord.expireMessages > 0) primaryRecord.expireMessages else secondaryRecord.expireMessages, @@ -4094,7 +4097,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da if (expiringProfileKeyCredentialString != null) { try { val columnDataBytes = Base64.decode(expiringProfileKeyCredentialString) - val columnData = ExpiringProfileKeyCredentialColumnData.parseFrom(columnDataBytes) + val columnData = ExpiringProfileKeyCredentialColumnData.ADAPTER.decode(columnDataBytes) if (Arrays.equals(columnData.profileKey.toByteArray(), profileKey)) { expiringProfileKeyCredential = ExpiringProfileKeyCredential(columnData.expiringProfileKeyCredential.toByteArray()) } else { @@ -4111,8 +4114,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val serializedWallpaper = cursor.requireBlob(WALLPAPER) val chatWallpaper: ChatWallpaper? = if (serializedWallpaper != null) { try { - ChatWallpaperFactory.create(Wallpaper.parseFrom(serializedWallpaper)) - } catch (e: InvalidProtocolBufferException) { + ChatWallpaperFactory.create(Wallpaper.ADAPTER.decode(serializedWallpaper)) + } catch (e: IOException) { Log.w(TAG, "Failed to parse wallpaper.", e) null } @@ -4124,8 +4127,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val serializedChatColors = cursor.requireBlob(CHAT_COLORS) val chatColors: ChatColors? = if (serializedChatColors != null) { try { - forChatColor(forLongValue(customChatColorsId), ChatColor.parseFrom(serializedChatColors)) - } catch (e: InvalidProtocolBufferException) { + forChatColor(forLongValue(customChatColorsId), ChatColor.ADAPTER.decode(serializedChatColors)) + } catch (e: IOException) { Log.w(TAG, "Failed to parse chat colors.", e) null } @@ -4206,15 +4209,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da var badgeList: BadgeList? = null if (serializedBadgeList != null) { try { - badgeList = BadgeList.parseFrom(serializedBadgeList) - } catch (e: InvalidProtocolBufferException) { + badgeList = BadgeList.ADAPTER.decode(serializedBadgeList) + } catch (e: IOException) { Log.w(TAG, e) } } val badges: List if (badgeList != null) { - val protoBadges = badgeList.badgesList + val protoBadges = badgeList.badges badges = ArrayList(protoBadges.size) for (protoBadge in protoBadges) { badges.add(Badges.fromDatabaseBadge(protoBadge)) @@ -4254,10 +4257,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } private fun getRecipientExtras(cursor: Cursor): RecipientExtras? { - return cursor.optionalBlob(EXTRAS).map { b: ByteArray? -> + return cursor.optionalBlob(EXTRAS).map { b: ByteArray -> try { - RecipientExtras.parseFrom(b) - } catch (e: InvalidProtocolBufferException) { + RecipientExtras.ADAPTER.decode(b) + } catch (e: IOException) { Log.w(TAG, e) throw AssertionError(e) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SentStorySyncManifest.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SentStorySyncManifest.kt index 5f332d4e53..dfa459d506 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SentStorySyncManifest.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SentStorySyncManifest.kt @@ -7,7 +7,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessageRe import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.SyncMessage /** * Represents a list of, or update to a list of, who can access a story through what @@ -84,12 +84,12 @@ data class SentStorySyncManifest( return SentStorySyncManifest(entries) } - fun fromRecipientsSet(recipients: List): SentStorySyncManifest { + fun fromRecipientsSet(recipients: List): SentStorySyncManifest { val entries = recipients.toSet().map { recipient -> Entry( - recipientId = RecipientId.from(ServiceId.parseOrThrow(recipient.destinationServiceId)), - allowedToReply = recipient.isAllowedToReply, - distributionLists = recipient.distributionListIdsList.map { DistributionId.from(it) } + recipientId = RecipientId.from(ServiceId.parseOrThrow(recipient.destinationServiceId!!)), + allowedToReply = recipient.isAllowedToReply!!, + distributionLists = recipient.distributionListIds.map { DistributionId.from(it) } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt index d4ef1d7654..35e6607b4f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt @@ -14,7 +14,6 @@ import android.preference.PreferenceManager import android.text.TextUtils import androidx.core.content.contentValuesOf import com.annimon.stream.Stream -import com.google.protobuf.InvalidProtocolBufferException import net.zetetic.database.sqlcipher.SQLiteDatabase import org.signal.core.util.CursorUtil import org.signal.core.util.Hex @@ -50,6 +49,7 @@ import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.io.File +import java.io.IOException import java.util.LinkedList import java.util.Locale import java.util.UUID @@ -1375,14 +1375,14 @@ object V149_LegacyMigrations : SignalDatabaseMigration { continue } try { - val hasReceiveLaterThanNotified: Boolean = ReactionList.parseFrom(reactions) - .reactionsList + val hasReceiveLaterThanNotified: Boolean = ReactionList.ADAPTER.decode(reactions) + .reactions .stream() .anyMatch { r: ReactionList.Reaction -> r.receivedTime > notifiedTimestamp } if (!hasReceiveLaterThanNotified) { smsIds.add(cursor.getLong(cursor.getColumnIndexOrThrow("_id"))) } - } catch (e: InvalidProtocolBufferException) { + } catch (e: IOException) { Log.e(TAG, e) } } @@ -1402,14 +1402,14 @@ object V149_LegacyMigrations : SignalDatabaseMigration { continue } try { - val hasReceiveLaterThanNotified: Boolean = ReactionList.parseFrom(reactions) - .reactionsList + val hasReceiveLaterThanNotified: Boolean = ReactionList.ADAPTER.decode(reactions) + .reactions .stream() .anyMatch { r: ReactionList.Reaction -> r.receivedTime > notifiedTimestamp } if (!hasReceiveLaterThanNotified) { mmsIds.add(cursor.getLong(cursor.getColumnIndexOrThrow("_id"))) } - } catch (e: InvalidProtocolBufferException) { + } catch (e: IOException) { Log.e(TAG, e) } } @@ -1490,7 +1490,7 @@ object V149_LegacyMigrations : SignalDatabaseMigration { for (entry: Map.Entry in entrySet) { val whereArgs = SqlUtil.buildArgs(entry.key.serialize()) val values = ContentValues(2) - values.put("chat_colors", entry.value.serialize().toByteArray()) + values.put("chat_colors", entry.value.serialize().encode()) values.put("custom_chat_colors_id", entry.value.id.longValue) db.update("recipient", values, where, whereArgs) } @@ -2678,9 +2678,9 @@ object V149_LegacyMigrations : SignalDatabaseMigration { private fun migrateReaction(db: SQLiteDatabase, cursor: Cursor, isMms: Boolean) { try { val messageId = CursorUtil.requireLong(cursor, "_id") - val reactionList = ReactionList.parseFrom(CursorUtil.requireBlob(cursor, "reactions")) + val reactionList = ReactionList.ADAPTER.decode(CursorUtil.requireBlob(cursor, "reactions")) - for (reaction in reactionList.reactionsList) { + for (reaction in reactionList.reactions) { val contentValues = ContentValues().apply { put("message_id", messageId) put("is_mms", if (isMms) 1 else 0) @@ -2691,7 +2691,7 @@ object V149_LegacyMigrations : SignalDatabaseMigration { } db.insert("reaction", null, contentValues) } - } catch (e: InvalidProtocolBufferException) { + } catch (e: IOException) { Log.w(TAG, "Failed to parse reaction!") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/AvatarPickerDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/AvatarPickerDatabase.kt index e42ccca622..897e70a7c8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/AvatarPickerDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/AvatarPickerDatabase.kt @@ -69,7 +69,7 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D val where = ID_WHERE val values = ContentValues(1) - values.put(AVATAR, avatar.toProto().toByteArray()) + values.put(AVATAR, avatar.toProto().encode()) db.update(TABLE_NAME, values, where, SqlUtil.buildArgs(databaseId.id)) } @@ -96,14 +96,14 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D if (databaseId is Avatar.DatabaseId.Saved) { val values = ContentValues(2) - values.put(AVATAR, avatar.toProto().toByteArray()) + values.put(AVATAR, avatar.toProto().encode()) db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(databaseId.id)) return avatar } else { val values = ContentValues(4) - values.put(AVATAR, avatar.toProto().toByteArray()) + values.put(AVATAR, avatar.toProto().encode()) if (groupId != null) { values.put(GROUP_ID, groupId.toString()) @@ -126,7 +126,7 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D while (it.moveToNext()) { val id = CursorUtil.requireLong(it, ID) val blob = CursorUtil.requireBlob(it, AVATAR) - val proto = CustomAvatar.parseFrom(blob) + val proto = CustomAvatar.ADAPTER.decode(blob) results.add(proto.toAvatar(id)) } } @@ -157,7 +157,7 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D while (it.moveToNext()) { val id = CursorUtil.requireLong(it, ID) val blob = CursorUtil.requireBlob(it, AVATAR) - val proto = CustomAvatar.parseFrom(blob) + val proto = CustomAvatar.ADAPTER.decode(blob) results.add(proto.toAvatar(id)) } } @@ -167,18 +167,18 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D private fun Avatar.toProto(): CustomAvatar { return when (this) { - is Avatar.Photo -> CustomAvatar.newBuilder().setPhoto(CustomAvatar.Photo.newBuilder().setUri(this.uri.toString())).build() - is Avatar.Text -> CustomAvatar.newBuilder().setText(CustomAvatar.Text.newBuilder().setText(this.text).setColors(this.color.code)).build() - is Avatar.Vector -> CustomAvatar.newBuilder().setVector(CustomAvatar.Vector.newBuilder().setKey(this.key).setColors(this.color.code)).build() + is Avatar.Photo -> CustomAvatar(photo = CustomAvatar.Photo(uri = this.uri.toString())) + is Avatar.Text -> CustomAvatar(text = CustomAvatar.Text(text = this.text, colors = this.color.code)) + is Avatar.Vector -> CustomAvatar(vector = CustomAvatar.Vector(key = this.key, colors = this.color.code)) else -> throw AssertionError() } } private fun CustomAvatar.toAvatar(id: Long): Avatar { return when { - hasPhoto() -> Avatar.Photo(Uri.parse(photo.uri), photo.size, Avatar.DatabaseId.Saved(id)) - hasText() -> Avatar.Text(text.text, Avatars.colorMap[text.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id)) - hasVector() -> Avatar.Vector(vector.key, Avatars.colorMap[vector.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id)) + photo != null -> Avatar.Photo(Uri.parse(photo.uri), photo.size, Avatar.DatabaseId.Saved(id)) + text != null -> Avatar.Text(text.text, Avatars.colorMap[text.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id)) + vector != null -> Avatar.Vector(vector.key, Avatars.colorMap[vector.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id)) else -> throw AssertionError() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/BodyRangeListSerializer.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/BodyRangeListSerializer.kt index e90a385d65..69b4cb0f24 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/BodyRangeListSerializer.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/BodyRangeListSerializer.kt @@ -5,8 +5,8 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList import org.thoughtcrime.securesms.util.Base64 object BodyRangeListSerializer : StringSerializer { - override fun serialize(data: BodyRangeList): String = Base64.encodeBytes(data.toByteArray()) - override fun deserialize(data: String): BodyRangeList = BodyRangeList.parseFrom(Base64.decode(data)) + override fun serialize(data: BodyRangeList): String = Base64.encodeBytes(data.encode()) + override fun deserialize(data: String): BodyRangeList = BodyRangeList.ADAPTER.decode(Base64.decode(data)) } fun BodyRangeList.serialize(): String { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DatabaseProtosUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/DatabaseProtosUtil.kt index 53e4e95181..82a033dcb9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DatabaseProtosUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DatabaseProtosUtil.kt @@ -2,46 +2,27 @@ package org.thoughtcrime.securesms.database.model -import com.google.protobuf.ByteString import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange +import org.whispersystems.signalservice.internal.push.BodyRange /** * Collection of extensions to make working with database protos cleaner. */ - -fun ByteArray.toProtoByteString(): ByteString { - return ByteString.copyFrom(this) -} - fun BodyRangeList.Builder.addStyle(style: BodyRangeList.BodyRange.Style, start: Int, length: Int): BodyRangeList.Builder { - addRanges( - BodyRangeList.BodyRange.newBuilder() - .setStyle(style) - .setStart(start) - .setLength(length) - ) - + ranges += BodyRangeList.BodyRange(style = style, start = start, length = length) return this } fun BodyRangeList.Builder.addLink(link: String, start: Int, length: Int): BodyRangeList.Builder { - addRanges( - BodyRangeList.BodyRange.newBuilder() - .setLink(link) - .setStart(start) - .setLength(length) - ) - + ranges += BodyRangeList.BodyRange(link = link, start = start, length = length) return this } fun BodyRangeList.Builder.addButton(label: String, action: String, start: Int, length: Int): BodyRangeList.Builder { - addRanges( - BodyRangeList.BodyRange.newBuilder() - .setButton(BodyRangeList.BodyRange.Button.newBuilder().setLabel(label).setAction(action)) - .setStart(start) - .setLength(length) + ranges += BodyRangeList.BodyRange( + button = BodyRangeList.BodyRange.Button(label = label, action = action), + start = start, + length = length ) return this @@ -52,7 +33,7 @@ fun List?.toBodyRangeList(): BodyRangeList? { return null } - val builder = BodyRangeList.newBuilder() + val builder = BodyRangeList.Builder() for (bodyRange in this) { var style: BodyRangeList.BodyRange.Style? = null @@ -65,7 +46,7 @@ fun List?.toBodyRangeList(): BodyRangeList? { else -> Unit } if (style != null) { - builder.addStyle(style, bodyRange.start, bodyRange.length) + builder.addStyle(style, bodyRange.start!!, bodyRange.length!!) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java index 99206f9b33..361f468f79 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java @@ -6,7 +6,6 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails; import org.thoughtcrime.securesms.util.Base64; -import org.thoughtcrime.securesms.util.Util; import java.io.IOException; import java.util.List; @@ -19,14 +18,14 @@ public final class GroupCallUpdateDetailsUtil { } public static @NonNull GroupCallUpdateDetails parse(@Nullable String body) { - GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetails.getDefaultInstance(); + GroupCallUpdateDetails groupCallUpdateDetails = new GroupCallUpdateDetails(); if (body == null) { return groupCallUpdateDetails; } try { - groupCallUpdateDetails = GroupCallUpdateDetails.parseFrom(Base64.decode(body)); + groupCallUpdateDetails = GroupCallUpdateDetails.ADAPTER.decode(Base64.decode(body)); } catch (IOException e) { Log.w(TAG, "Group call update details could not be read", e); } @@ -35,14 +34,10 @@ public final class GroupCallUpdateDetailsUtil { } public static @NonNull String createUpdatedBody(@NonNull GroupCallUpdateDetails groupCallUpdateDetails, @NonNull List inCallUuids, boolean isCallFull) { - GroupCallUpdateDetails.Builder builder = groupCallUpdateDetails.toBuilder() - .setIsCallFull(isCallFull) - .clearInCallUuids(); + GroupCallUpdateDetails.Builder builder = groupCallUpdateDetails.newBuilder() + .isCallFull(isCallFull) + .inCallUuids(inCallUuids); - if (Util.hasItems(inCallUuids)) { - builder.addAllInCallUuids(inCallUuids); - } - - return Base64.encodeBytes(builder.build().toByteArray()); + return Base64.encodeBytes(builder.build().encode()); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java index 7be56d8053..2e268d4acb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java @@ -12,8 +12,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.DateUtils; -import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.ArrayList; import java.util.List; @@ -53,14 +53,14 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.Spannabl } private @NonNull String createString() { - String time = DateUtils.getTimeString(context, Locale.getDefault(), groupCallUpdateDetails.getStartedCallTimestamp()); + String time = DateUtils.getTimeString(context, Locale.getDefault(), groupCallUpdateDetails.startedCallTimestamp); switch (joinedMembers.size()) { case 0: return withTime ? context.getString(R.string.MessageRecord_group_call_s, time) : context.getString(R.string.MessageRecord_group_call); case 1: - if (joinedMembers.get(0).toString().equals(groupCallUpdateDetails.getStartedCallUuid())) { + if (joinedMembers.get(0).toString().equals(groupCallUpdateDetails.startedCallUuid)) { if (Objects.equals(joinedMembers.get(0), selfAci)) { return withTime ? context.getString(R.string.MessageRecord_you_started_a_group_call_s, time) : context.getString(R.string.MessageRecord_you_started_a_group_call); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt index b7b8942b39..3a92cc2665 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt @@ -87,7 +87,7 @@ class GroupRecord( val membershipAdditionAccessControl: GroupAccessControl get() { return if (isV2Group) { - if (requireV2GroupProperties().decryptedGroup.accessControl.members == AccessControl.AccessRequired.MEMBER) { + if (requireV2GroupProperties().decryptedGroup.accessControl!!.members == AccessControl.AccessRequired.MEMBER) { GroupAccessControl.ALL_MEMBERS } else { GroupAccessControl.ONLY_ADMINS @@ -105,7 +105,7 @@ class GroupRecord( val attributesAccessControl: GroupAccessControl get() { return if (isV2Group) { - if (requireV2GroupProperties().decryptedGroup.accessControl.attributes == AccessControl.AccessRequired.MEMBER) { + if (requireV2GroupProperties().decryptedGroup.accessControl!!.attributes == AccessControl.AccessRequired.MEMBER) { GroupAccessControl.ALL_MEMBERS } else { GroupAccessControl.ONLY_ADMINS @@ -121,7 +121,7 @@ class GroupRecord( if (isV2Group && memberLevel(Recipient.self()) == GroupTable.MemberLevel.ADMINISTRATOR) { requireV2GroupProperties() .decryptedGroup - .requestingMembersCount + .requestingMembers.size } else { 0 } @@ -175,7 +175,7 @@ class GroupRecord( if (isV2Group) { val serviceId = recipient.serviceId if (serviceId.isPresent) { - return DecryptedGroupUtil.findPendingByServiceId(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get()) + return DecryptedGroupUtil.findPendingByServiceId(requireV2GroupProperties().decryptedGroup.pendingMembers, serviceId.get()) .isPresent } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java index c7ea885011..05103794cc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java @@ -12,8 +12,6 @@ import androidx.annotation.StringRes; import androidx.annotation.VisibleForTesting; import androidx.core.content.ContextCompat; -import com.google.protobuf.ByteString; - import org.signal.core.util.StringUtil; import org.signal.storageservice.protos.groups.AccessControl; import org.signal.storageservice.protos.groups.Member; @@ -51,6 +49,8 @@ import java.util.UUID; import java.util.function.Consumer; import java.util.stream.Collectors; +import okio.ByteString; + final class GroupsV2UpdateMessageProducer { @NonNull private final Context context; @@ -72,26 +72,32 @@ final class GroupsV2UpdateMessageProducer { *

* When the revision of the group is 0, the change is very noisy and only the editor is useful. */ - UpdateDescription describeNewGroup(@NonNull DecryptedGroup group, @NonNull DecryptedGroupChange decryptedGroupChange) { - Optional selfPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfIds.getAci()); - if (!selfPending.isPresent() && selfIds.getPni() != null) { - selfPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfIds.getPni()); - } + UpdateDescription describeNewGroup(@Nullable DecryptedGroup group, @Nullable DecryptedGroupChange decryptedGroupChange) { + Optional selfPending = Optional.empty(); - if (selfPending.isPresent()) { - return updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, selfPending.get().getAddedByAci(), R.drawable.ic_update_group_add_16); - } - - ByteString foundingMemberUuid = decryptedGroupChange.getEditorServiceIdBytes(); - if (!foundingMemberUuid.isEmpty()) { - if (selfIds.matches(foundingMemberUuid)) { - return updateDescription(context.getString(R.string.MessageRecord_you_created_the_group), R.drawable.ic_update_group_16); - } else { - return updateDescription(R.string.MessageRecord_s_added_you, foundingMemberUuid, R.drawable.ic_update_group_add_16); + if (group != null) { + selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.getAci()); + if (selfPending.isEmpty() && selfIds.getPni() != null) { + selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.getPni()); } } - if (DecryptedGroupUtil.findMemberByAci(group.getMembersList(), selfIds.getAci()).isPresent()) { + if (selfPending.isPresent()) { + return updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, selfPending.get().addedByAci, R.drawable.ic_update_group_add_16); + } + + if (decryptedGroupChange != null) { + ByteString foundingMemberUuid = decryptedGroupChange.editorServiceIdBytes; + if (foundingMemberUuid.size() > 0) { + if (selfIds.matches(foundingMemberUuid)) { + return updateDescription(context.getString(R.string.MessageRecord_you_created_the_group), R.drawable.ic_update_group_16); + } else { + return updateDescription(R.string.MessageRecord_s_added_you, foundingMemberUuid, R.drawable.ic_update_group_add_16); + } + } + } + + if (group != null && DecryptedGroupUtil.findMemberByAci(group.members, selfIds.getAci()).isPresent()) { return updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16); } else { return updateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16); @@ -99,14 +105,14 @@ final class GroupsV2UpdateMessageProducer { } List describeChanges(@Nullable DecryptedGroup previousGroupState, @NonNull DecryptedGroupChange change) { - if (DecryptedGroup.getDefaultInstance().equals(previousGroupState)) { + if (new DecryptedGroup().equals(previousGroupState)) { previousGroupState = null; } List updates = new LinkedList<>(); - boolean editorUnknown = change.getEditorServiceIdBytes().isEmpty(); - ServiceId editorServiceId = editorUnknown ? null : ServiceId.parseOrNull(change.getEditorServiceIdBytes()); + boolean editorUnknown = change.editorServiceIdBytes.size() == 0; + ServiceId editorServiceId = editorUnknown ? null : ServiceId.parseOrNull(change.editorServiceIdBytes); if (editorServiceId == null || editorServiceId.isUnknown()) { editorUnknown = true; @@ -172,12 +178,12 @@ final class GroupsV2UpdateMessageProducer { * Handles case of future protocol versions where we don't know what has changed. */ private void describeUnknownChange(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_updated_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_16)); + updates.add(updateDescription(R.string.MessageRecord_s_updated_group, change.editorServiceIdBytes, R.drawable.ic_update_group_16)); } } @@ -186,25 +192,25 @@ final class GroupsV2UpdateMessageProducer { } private void describeMemberAdditions(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - for (DecryptedMember member : change.getNewMembersList()) { - boolean newMemberIsYou = selfIds.matches(member.getAciBytes()); + for (DecryptedMember member : change.newMembers) { + boolean newMemberIsYou = selfIds.matches(member.aciBytes); if (editorIsYou) { if (newMemberIsYou) { updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group_via_the_group_link), R.drawable.ic_update_group_accept_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_you_added_s, member.getAciBytes(), R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_you_added_s, member.aciBytes, R.drawable.ic_update_group_add_16)); } } else { if (newMemberIsYou) { - updates.add(0, updateDescription(R.string.MessageRecord_s_added_you, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16)); + updates.add(0, updateDescription(R.string.MessageRecord_s_added_you, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16)); } else { - if (member.getAciBytes().equals(change.getEditorServiceIdBytes())) { - updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group_via_the_group_link, member.getAciBytes(), R.drawable.ic_update_group_accept_16)); + if (member.aciBytes.equals(change.editorServiceIdBytes)) { + updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group_via_the_group_link, member.aciBytes, R.drawable.ic_update_group_accept_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_added_s, change.getEditorServiceIdBytes(), member.getAciBytes(), R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_s_added_s, change.editorServiceIdBytes, member.aciBytes, R.drawable.ic_update_group_add_16)); } } } @@ -212,21 +218,21 @@ final class GroupsV2UpdateMessageProducer { } private void describeUnknownEditorMemberAdditions(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (DecryptedMember member : change.getNewMembersList()) { - boolean newMemberIsYou = selfIds.matches(member.getAciBytes()); + for (DecryptedMember member : change.newMembers) { + boolean newMemberIsYou = selfIds.matches(member.aciBytes); if (newMemberIsYou) { updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, member.getAciBytes(), R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, member.aciBytes, R.drawable.ic_update_group_add_16)); } } } private void describeMemberRemovals(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - for (ByteString member : change.getDeleteMembersList()) { + for (ByteString member : change.deleteMembers) { boolean removedMemberIsYou = selfIds.matches(member); if (editorIsYou) { @@ -237,12 +243,12 @@ final class GroupsV2UpdateMessageProducer { } } else { if (removedMemberIsYou) { - updates.add(updateDescription(R.string.MessageRecord_s_removed_you_from_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_remove_16)); + updates.add(updateDescription(R.string.MessageRecord_s_removed_you_from_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_remove_16)); } else { - if (member.equals(change.getEditorServiceIdBytes())) { + if (member.equals(change.editorServiceIdBytes)) { updates.add(updateDescription(R.string.MessageRecord_s_left_the_group, member, R.drawable.ic_update_group_leave_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_removed_s, change.getEditorServiceIdBytes(), member, R.drawable.ic_update_group_remove_16)); + updates.add(updateDescription(R.string.MessageRecord_s_removed_s, change.editorServiceIdBytes, member, R.drawable.ic_update_group_remove_16)); } } } @@ -250,7 +256,7 @@ final class GroupsV2UpdateMessageProducer { } private void describeUnknownEditorMemberRemovals(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (ByteString member : change.getDeleteMembersList()) { + for (ByteString member : change.deleteMembers) { boolean removedMemberIsYou = selfIds.matches(member); if (removedMemberIsYou) { @@ -262,29 +268,29 @@ final class GroupsV2UpdateMessageProducer { } private void describeModifyMemberRoles(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - for (DecryptedModifyMemberRole roleChange : change.getModifyMemberRolesList()) { - boolean changedMemberIsYou = selfIds.matches(roleChange.getAciBytes()); - if (roleChange.getRole() == Member.Role.ADMINISTRATOR) { + for (DecryptedModifyMemberRole roleChange : change.modifyMemberRoles) { + boolean changedMemberIsYou = selfIds.matches(roleChange.aciBytes); + if (roleChange.role == Member.Role.ADMINISTRATOR) { if (editorIsYou) { - updates.add(updateDescription(R.string.MessageRecord_you_made_s_an_admin, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_you_made_s_an_admin, roleChange.aciBytes, R.drawable.ic_update_group_role_16)); } else { if (changedMemberIsYou) { - updates.add(updateDescription(R.string.MessageRecord_s_made_you_an_admin, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_made_you_an_admin, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_made_s_an_admin, change.getEditorServiceIdBytes(), roleChange.getAciBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_made_s_an_admin, change.editorServiceIdBytes, roleChange.aciBytes, R.drawable.ic_update_group_role_16)); } } } else { if (editorIsYou) { - updates.add(updateDescription(R.string.MessageRecord_you_revoked_admin_privileges_from_s, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_you_revoked_admin_privileges_from_s, roleChange.aciBytes, R.drawable.ic_update_group_role_16)); } else { if (changedMemberIsYou) { - updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_admin_privileges, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_admin_privileges, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_revoked_admin_privileges_from_s, change.getEditorServiceIdBytes(), roleChange.getAciBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_revoked_admin_privileges_from_s, change.editorServiceIdBytes, roleChange.aciBytes, R.drawable.ic_update_group_role_16)); } } } @@ -292,37 +298,37 @@ final class GroupsV2UpdateMessageProducer { } private void describeUnknownEditorModifyMemberRoles(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (DecryptedModifyMemberRole roleChange : change.getModifyMemberRolesList()) { - boolean changedMemberIsYou = selfIds.matches(roleChange.getAciBytes()); + for (DecryptedModifyMemberRole roleChange : change.modifyMemberRoles) { + boolean changedMemberIsYou = selfIds.matches(roleChange.aciBytes); - if (roleChange.getRole() == Member.Role.ADMINISTRATOR) { + if (roleChange.role == Member.Role.ADMINISTRATOR) { if (changedMemberIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_now_an_admin), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_is_now_an_admin, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_is_now_an_admin, roleChange.aciBytes, R.drawable.ic_update_group_role_16)); } } else { if (changedMemberIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_no_longer_an_admin), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_an_admin, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_an_admin, roleChange.aciBytes, R.drawable.ic_update_group_role_16)); } } } } private void describeInvitations(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); int notYouInviteCount = 0; - for (DecryptedPendingMember invitee : change.getNewPendingMembersList()) { - boolean newMemberIsYou = selfIds.matches(invitee.getServiceIdBytes()); + for (DecryptedPendingMember invitee : change.newPendingMembers) { + boolean newMemberIsYou = selfIds.matches(invitee.serviceIdBytes); if (newMemberIsYou) { - updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16)); + updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16)); } else { if (editorIsYou) { - updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, invitee.getServiceIdBytes(), R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, invitee.serviceIdBytes, R.drawable.ic_update_group_add_16)); } else { notYouInviteCount++; } @@ -330,23 +336,23 @@ final class GroupsV2UpdateMessageProducer { } if (notYouInviteCount > 0) { - updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, notYouInviteCount, change.getEditorServiceIdBytes(), notYouInviteCount, R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, notYouInviteCount, change.editorServiceIdBytes, notYouInviteCount, R.drawable.ic_update_group_add_16)); } } private void describeUnknownEditorInvitations(@NonNull DecryptedGroupChange change, @NonNull List updates) { int notYouInviteCount = 0; - for (DecryptedPendingMember invitee : change.getNewPendingMembersList()) { - boolean newMemberIsYou = selfIds.matches(invitee.getServiceIdBytes()); + for (DecryptedPendingMember invitee : change.newPendingMembers) { + boolean newMemberIsYou = selfIds.matches(invitee.serviceIdBytes); if (newMemberIsYou) { - UUID uuid = UuidUtil.fromByteStringOrUnknown(invitee.getAddedByAci()); + UUID uuid = UuidUtil.fromByteStringOrUnknown(invitee.addedByAci); if (UuidUtil.UNKNOWN_UUID.equals(uuid)) { updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_were_invited_to_the_group), R.drawable.ic_update_group_add_16)); } else { - updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, invitee.getAddedByAci(), R.drawable.ic_update_group_add_16)); + updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, invitee.addedByAci, R.drawable.ic_update_group_add_16)); } } else { notYouInviteCount++; @@ -359,19 +365,19 @@ final class GroupsV2UpdateMessageProducer { } private void describeRevokedInvitations(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); int notDeclineCount = 0; - for (DecryptedPendingMemberRemoval invitee : change.getDeletePendingMembersList()) { - boolean decline = invitee.getServiceIdBytes().equals(change.getEditorServiceIdBytes()); + for (DecryptedPendingMemberRemoval invitee : change.deletePendingMembers) { + boolean decline = invitee.serviceIdBytes.equals(change.editorServiceIdBytes); if (decline) { if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_declined_the_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); } else { updates.add(updateDescription(context.getString(R.string.MessageRecord_someone_declined_an_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); } - } else if (selfIds.matches(invitee.getServiceIdBytes())) { - updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_decline_16)); + } else if (selfIds.matches(invitee.serviceIdBytes)) { + updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_decline_16)); } else { notDeclineCount++; } @@ -381,7 +387,7 @@ final class GroupsV2UpdateMessageProducer { if (editorIsYou) { updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_you_revoked_invites, notDeclineCount, notDeclineCount), R.drawable.ic_update_group_decline_16)); } else { - updates.add(updateDescription(R.plurals.MessageRecord_s_revoked_invites, notDeclineCount, change.getEditorServiceIdBytes(), notDeclineCount, R.drawable.ic_update_group_decline_16)); + updates.add(updateDescription(R.plurals.MessageRecord_s_revoked_invites, notDeclineCount, change.editorServiceIdBytes, notDeclineCount, R.drawable.ic_update_group_decline_16)); } } } @@ -389,8 +395,8 @@ final class GroupsV2UpdateMessageProducer { private void describeUnknownEditorRevokedInvitations(@NonNull DecryptedGroupChange change, @NonNull List updates) { int notDeclineCount = 0; - for (DecryptedPendingMemberRemoval invitee : change.getDeletePendingMembersList()) { - boolean inviteeWasYou = selfIds.matches(invitee.getServiceIdBytes()); + for (DecryptedPendingMemberRemoval invitee : change.deletePendingMembers) { + boolean inviteeWasYou = selfIds.matches(invitee.serviceIdBytes); if (inviteeWasYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); @@ -405,10 +411,10 @@ final class GroupsV2UpdateMessageProducer { } private void describePromotePending(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - for (DecryptedMember newMember : change.getPromotePendingMembersList()) { - ByteString aci = newMember.getAciBytes(); + for (DecryptedMember newMember : change.promotePendingMembers) { + ByteString aci = newMember.aciBytes; boolean newMemberIsYou = selfIds.matches(aci); if (editorIsYou) { @@ -419,12 +425,12 @@ final class GroupsV2UpdateMessageProducer { } } else { if (newMemberIsYou) { - updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16)); } else { - if (aci.equals(change.getEditorServiceIdBytes())) { + if (aci.equals(change.editorServiceIdBytes)) { updates.add(updateDescription(R.string.MessageRecord_s_accepted_invite, aci, R.drawable.ic_update_group_accept_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.getEditorServiceIdBytes(), aci, R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.editorServiceIdBytes, aci, R.drawable.ic_update_group_add_16)); } } } @@ -432,8 +438,8 @@ final class GroupsV2UpdateMessageProducer { } private void describeUnknownEditorPromotePending(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (DecryptedMember newMember : change.getPromotePendingMembersList()) { - ByteString aci = newMember.getAciBytes(); + for (DecryptedMember newMember : change.promotePendingMembers) { + ByteString aci = newMember.aciBytes; boolean newMemberIsYou = selfIds.matches(aci); if (newMemberIsYou) { @@ -445,116 +451,116 @@ final class GroupsV2UpdateMessageProducer { } private void describeNewTitle(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - if (change.hasNewTitle()) { - String newTitle = StringUtil.isolateBidi(change.getNewTitle().getValue()); + if (change.newTitle != null) { + String newTitle = StringUtil.isolateBidi(change.newTitle.value_); if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_name_to_s, newTitle), R.drawable.ic_update_group_name_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_name_to_s, change.getEditorServiceIdBytes(), newTitle, R.drawable.ic_update_group_name_16)); + updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_name_to_s, change.editorServiceIdBytes, newTitle, R.drawable.ic_update_group_name_16)); } } } private void describeNewDescription(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - if (change.hasNewDescription()) { + if (change.newDescription != null) { if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_description), R.drawable.ic_update_group_name_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_description, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_name_16)); + updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_description, change.editorServiceIdBytes, R.drawable.ic_update_group_name_16)); } } } private void describeUnknownEditorNewTitle(@NonNull DecryptedGroupChange change, @NonNull List updates) { - if (change.hasNewTitle()) { - updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(change.getNewTitle().getValue())), R.drawable.ic_update_group_name_16)); + if (change.newTitle != null) { + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(change.newTitle.value_)), R.drawable.ic_update_group_name_16)); } } private void describeUnknownEditorNewDescription(@NonNull DecryptedGroupChange change, @NonNull List updates) { - if (change.hasNewDescription()) { + if (change.newDescription != null) { updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_description_has_changed), R.drawable.ic_update_group_name_16)); } } private void describeNewAvatar(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - if (change.hasNewAvatar()) { + if (change.newAvatar != null) { if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_avatar), R.drawable.ic_update_group_avatar_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_avatar, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_avatar_16)); + updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_avatar, change.editorServiceIdBytes, R.drawable.ic_update_group_avatar_16)); } } } private void describeUnknownEditorNewAvatar(@NonNull DecryptedGroupChange change, @NonNull List updates) { - if (change.hasNewAvatar()) { + if (change.newAvatar != null) { updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_group_avatar_has_been_changed), R.drawable.ic_update_group_avatar_16)); } } void describeNewTimer(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - if (change.hasNewTimer()) { - String time = ExpirationUtil.getExpirationDisplayValue(context, change.getNewTimer().getDuration()); + if (change.newTimer != null) { + String time = ExpirationUtil.getExpirationDisplayValue(context, change.newTimer.duration); if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, change.getEditorServiceIdBytes(), time, R.drawable.ic_update_timer_16)); + updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, change.editorServiceIdBytes, time, R.drawable.ic_update_timer_16)); } } } private void describeUnknownEditorNewTimer(@NonNull DecryptedGroupChange change, @NonNull List updates) { - if (change.hasNewTimer()) { - String time = ExpirationUtil.getExpirationDisplayValue(context, change.getNewTimer().getDuration()); + if (change.newTimer != null) { + String time = ExpirationUtil.getExpirationDisplayValue(context, change.newTimer.duration); updates.add(updateDescription(context.getString(R.string.MessageRecord_disappearing_message_time_set_to_s, time), R.drawable.ic_update_timer_16)); } } private void describeNewAttributeAccess(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - if (change.getNewAttributeAccess() != AccessControl.AccessRequired.UNKNOWN) { - String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewAttributeAccess()); + if (change.newAttributeAccess != AccessControl.AccessRequired.UNKNOWN) { + String accessLevel = GV2AccessLevelUtil.toString(context, change.newAttributeAccess); if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_info_to_s, accessLevel), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_info_to_s, change.getEditorServiceIdBytes(), accessLevel, R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_info_to_s, change.editorServiceIdBytes, accessLevel, R.drawable.ic_update_group_role_16)); } } } private void describeUnknownEditorNewAttributeAccess(@NonNull DecryptedGroupChange change, @NonNull List updates) { - if (change.getNewAttributeAccess() != AccessControl.AccessRequired.UNKNOWN) { - String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewAttributeAccess()); + if (change.newAttributeAccess != AccessControl.AccessRequired.UNKNOWN) { + String accessLevel = GV2AccessLevelUtil.toString(context, change.newAttributeAccess); updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_info_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16)); } } private void describeNewMembershipAccess(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - if (change.getNewMemberAccess() != AccessControl.AccessRequired.UNKNOWN) { - String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewMemberAccess()); + if (change.newMemberAccess != AccessControl.AccessRequired.UNKNOWN) { + String accessLevel = GV2AccessLevelUtil.toString(context, change.newMemberAccess); if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_membership_to_s, accessLevel), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_membership_to_s, change.getEditorServiceIdBytes(), accessLevel, R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_membership_to_s, change.editorServiceIdBytes, accessLevel, R.drawable.ic_update_group_role_16)); } } } private void describeUnknownEditorNewMembershipAccess(@NonNull DecryptedGroupChange change, @NonNull List updates) { - if (change.getNewMemberAccess() != AccessControl.AccessRequired.UNKNOWN) { - String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewMemberAccess()); + if (change.newMemberAccess != AccessControl.AccessRequired.UNKNOWN) { + String accessLevel = GV2AccessLevelUtil.toString(context, change.newMemberAccess); updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_membership_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16)); } } @@ -565,14 +571,15 @@ final class GroupsV2UpdateMessageProducer { { AccessControl.AccessRequired previousAccessControl = null; - if (previousGroupState != null) { - previousAccessControl = previousGroupState.getAccessControl().getAddFromInviteLink(); + if (previousGroupState != null && previousGroupState.accessControl != null) { + previousAccessControl = previousGroupState.accessControl.addFromInviteLink; } - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); boolean groupLinkEnabled = false; - switch (change.getNewInviteLinkAccess()) { + //noinspection EnhancedSwitchMigration + switch (change.newInviteLinkAccess) { case ANY: groupLinkEnabled = true; if (editorIsYou) { @@ -583,9 +590,9 @@ final class GroupsV2UpdateMessageProducer { } } else { if (previousAccessControl == AccessControl.AccessRequired.ADMINISTRATOR) { - updates.add(updateDescription(R.string.MessageRecord_s_turned_off_admin_approval_for_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_turned_off_admin_approval_for_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_off, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_off, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } } break; @@ -599,9 +606,9 @@ final class GroupsV2UpdateMessageProducer { } } else { if (previousAccessControl == AccessControl.AccessRequired.ANY) { - updates.add(updateDescription(R.string.MessageRecord_s_turned_on_admin_approval_for_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_turned_on_admin_approval_for_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_on, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_on, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } } break; @@ -609,16 +616,16 @@ final class GroupsV2UpdateMessageProducer { if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_off_the_group_link), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_turned_off_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_turned_off_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } break; } - if (!groupLinkEnabled && change.getNewInviteLinkPassword().size() > 0) { + if (!groupLinkEnabled && change.newInviteLinkPassword.size() > 0) { if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_reset_the_group_link), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_reset_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_reset_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } } } @@ -629,11 +636,12 @@ final class GroupsV2UpdateMessageProducer { { AccessControl.AccessRequired previousAccessControl = null; - if (previousGroupState != null) { - previousAccessControl = previousGroupState.getAccessControl().getAddFromInviteLink(); + if (previousGroupState != null && previousGroupState.accessControl != null) { + previousAccessControl = previousGroupState.accessControl.addFromInviteLink; } - switch (change.getNewInviteLinkAccess()) { + //noinspection EnhancedSwitchMigration + switch (change.newInviteLinkAccess) { case ANY: if (previousAccessControl == AccessControl.AccessRequired.ADMINISTRATOR) { updates.add(updateDescription(context.getString(R.string.MessageRecord_the_admin_approval_for_the_group_link_has_been_turned_off), R.drawable.ic_update_group_role_16)); @@ -653,69 +661,69 @@ final class GroupsV2UpdateMessageProducer { break; } - if (change.getNewInviteLinkPassword().size() > 0) { + if (change.newInviteLinkPassword.size() > 0) { updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_reset), R.drawable.ic_update_group_role_16)); } } private void describeRequestingMembers(@NonNull DecryptedGroupChange change, @NonNull List updates) { - Set deleteRequestingUuids = new HashSet<>(change.getDeleteRequestingMembersList()); + Set deleteRequestingUuids = new HashSet<>(change.deleteRequestingMembers); - for (DecryptedRequestingMember member : change.getNewRequestingMembersList()) { - boolean requestingMemberIsYou = selfIds.matches(member.getAciBytes()); + for (DecryptedRequestingMember member : change.newRequestingMembers) { + boolean requestingMemberIsYou = selfIds.matches(member.aciBytes); if (requestingMemberIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_sent_a_request_to_join_the_group), R.drawable.ic_update_group_16)); } else { - if (deleteRequestingUuids.contains(member.getAciBytes())) { + if (deleteRequestingUuids.contains(member.aciBytes)) { updates.add(updateDescription(R.plurals.MessageRecord_s_requested_and_cancelled_their_request_to_join_via_the_group_link, - change.getDeleteRequestingMembersCount(), - member.getAciBytes(), - change.getDeleteRequestingMembersCount(), + change.deleteRequestingMembers.size(), + member.aciBytes, + change.deleteRequestingMembers.size(), R.drawable.ic_update_group_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_requested_to_join_via_the_group_link, member.getAciBytes(), R.drawable.ic_update_group_16)); + updates.add(updateDescription(R.string.MessageRecord_s_requested_to_join_via_the_group_link, member.aciBytes, R.drawable.ic_update_group_16)); } } } } private void describeRequestingMembersApprovals(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (DecryptedApproveMember requestingMember : change.getPromoteRequestingMembersList()) { - boolean requestingMemberIsYou = selfIds.matches(requestingMember.getAciBytes()); + for (DecryptedApproveMember requestingMember : change.promoteRequestingMembers) { + boolean requestingMemberIsYou = selfIds.matches(requestingMember.aciBytes); if (requestingMemberIsYou) { - updates.add(updateDescription(R.string.MessageRecord_s_approved_your_request_to_join_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_accept_16)); + updates.add(updateDescription(R.string.MessageRecord_s_approved_your_request_to_join_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_accept_16)); } else { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); if (editorIsYou) { - updates.add(updateDescription(R.string.MessageRecord_you_approved_a_request_to_join_the_group_from_s, requestingMember.getAciBytes(), R.drawable.ic_update_group_accept_16)); + updates.add(updateDescription(R.string.MessageRecord_you_approved_a_request_to_join_the_group_from_s, requestingMember.aciBytes, R.drawable.ic_update_group_accept_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_approved_a_request_to_join_the_group_from_s, change.getEditorServiceIdBytes(), requestingMember.getAciBytes(), R.drawable.ic_update_group_accept_16)); + updates.add(updateDescription(R.string.MessageRecord_s_approved_a_request_to_join_the_group_from_s, change.editorServiceIdBytes, requestingMember.aciBytes, R.drawable.ic_update_group_accept_16)); } } } } private void describeUnknownEditorRequestingMembersApprovals(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (DecryptedApproveMember requestingMember : change.getPromoteRequestingMembersList()) { - boolean requestingMemberIsYou = selfIds.matches(requestingMember.getAciBytes()); + for (DecryptedApproveMember requestingMember : change.promoteRequestingMembers) { + boolean requestingMemberIsYou = selfIds.matches(requestingMember.aciBytes); if (requestingMemberIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_approved), R.drawable.ic_update_group_accept_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_approved, requestingMember.getAciBytes(), R.drawable.ic_update_group_accept_16)); + updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_approved, requestingMember.aciBytes, R.drawable.ic_update_group_accept_16)); } } } private void describeRequestingMembersDeletes(@NonNull DecryptedGroupChange change, @NonNull List updates) { - Set newRequestingUuids = change.getNewRequestingMembersList().stream().map(DecryptedRequestingMember::getAciBytes).collect(Collectors.toSet()); + Set newRequestingUuids = change.newRequestingMembers.stream().map(m -> m.aciBytes).collect(Collectors.toSet()); - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - for (ByteString requestingMember : change.getDeleteRequestingMembersList()) { + for (ByteString requestingMember : change.deleteRequestingMembers) { if (newRequestingUuids.contains(requestingMember)) { continue; } @@ -729,19 +737,19 @@ final class GroupsV2UpdateMessageProducer { updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_denied_by_an_admin), R.drawable.ic_update_group_decline_16)); } } else { - boolean editorIsCanceledMember = change.getEditorServiceIdBytes().equals(requestingMember); + boolean editorIsCanceledMember = change.editorServiceIdBytes.equals(requestingMember); if (editorIsCanceledMember) { updates.add(updateDescription(R.string.MessageRecord_s_canceled_their_request_to_join_the_group, requestingMember, R.drawable.ic_update_group_decline_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_denied_a_request_to_join_the_group_from_s, change.getEditorServiceIdBytes(), requestingMember, R.drawable.ic_update_group_decline_16)); + updates.add(updateDescription(R.string.MessageRecord_s_denied_a_request_to_join_the_group_from_s, change.editorServiceIdBytes, requestingMember, R.drawable.ic_update_group_decline_16)); } } } } private void describeUnknownEditorRequestingMembersDeletes(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (ByteString requestingMember : change.getDeleteRequestingMembersList()) { + for (ByteString requestingMember : change.deleteRequestingMembers) { boolean requestingMemberIsYou = selfIds.matches(requestingMember); if (requestingMemberIsYou) { @@ -753,36 +761,36 @@ final class GroupsV2UpdateMessageProducer { } private void describeAnnouncementGroupChange(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - if (change.getNewIsAnnouncementGroup() == EnabledState.ENABLED) { + if (change.newIsAnnouncementGroup == EnabledState.ENABLED) { if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_only_admins_to_send), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_allow_only_admins_to_send, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_allow_only_admins_to_send, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } - } else if (change.getNewIsAnnouncementGroup() == EnabledState.DISABLED) { + } else if (change.newIsAnnouncementGroup == EnabledState.DISABLED) { if (editorIsYou) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_all_members_to_send), R.drawable.ic_update_group_role_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_allow_all_members_to_send, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16)); + updates.add(updateDescription(R.string.MessageRecord_s_allow_all_members_to_send, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16)); } } } private void describeUnknownEditorAnnouncementGroupChange(@NonNull DecryptedGroupChange change, @NonNull List updates) { - if (change.getNewIsAnnouncementGroup() == EnabledState.ENABLED) { + if (change.newIsAnnouncementGroup == EnabledState.ENABLED) { updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_only_admins_to_send), R.drawable.ic_update_group_role_16)); - } else if (change.getNewIsAnnouncementGroup() == EnabledState.DISABLED) { + } else if (change.newIsAnnouncementGroup == EnabledState.DISABLED) { updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_all_members_to_send), R.drawable.ic_update_group_role_16)); } } private void describePromotePendingPniAci(@NonNull DecryptedGroupChange change, @NonNull List updates) { - boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes()); + boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes); - for (DecryptedMember newMember : change.getPromotePendingPniAciMembersList()) { - ByteString uuid = newMember.getAciBytes(); + for (DecryptedMember newMember : change.promotePendingPniAciMembers) { + ByteString uuid = newMember.aciBytes; boolean newMemberIsYou = selfIds.matches(uuid); if (editorIsYou) { @@ -793,12 +801,12 @@ final class GroupsV2UpdateMessageProducer { } } else { if (newMemberIsYou) { - updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16)); } else { - if (uuid.equals(change.getEditorServiceIdBytes())) { + if (uuid.equals(change.editorServiceIdBytes)) { updates.add(updateDescription(R.string.MessageRecord_s_accepted_invite, uuid, R.drawable.ic_update_group_accept_16)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.getEditorServiceIdBytes(), uuid, R.drawable.ic_update_group_add_16)); + updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.editorServiceIdBytes, uuid, R.drawable.ic_update_group_add_16)); } } } @@ -806,8 +814,8 @@ final class GroupsV2UpdateMessageProducer { } private void describeUnknownEditorPromotePendingPniAci(@NonNull DecryptedGroupChange change, @NonNull List updates) { - for (DecryptedMember newMember : change.getPromotePendingPniAciMembersList()) { - ByteString aci = newMember.getAciBytes(); + for (DecryptedMember newMember : change.promotePendingPniAciMembers) { + ByteString aci = newMember.aciBytes; boolean newMemberIsYou = selfIds.matches(aci); if (newMemberIsYou) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageLogEntry.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageLogEntry.kt index 30e788a5ce..63835451fd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageLogEntry.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageLogEntry.kt @@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.database.model import org.thoughtcrime.securesms.recipients.RecipientId import org.whispersystems.signalservice.api.crypto.ContentHint -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.Content /** * Model class for reading from the [org.thoughtcrime.securesms.database.MessageSendLogTables]. @@ -10,7 +10,7 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos data class MessageLogEntry( val recipientId: RecipientId, val dateSent: Long, - val content: SignalServiceProtos.Content, + val content: Content, val contentHint: ContentHint, @get:JvmName("isUrgent") val urgent: Boolean, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index f708c08dcd..75b9c6c671 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -31,8 +31,6 @@ import androidx.annotation.WorkerThread; import androidx.core.content.ContextCompat; import com.annimon.stream.Stream; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; import org.signal.core.util.StringUtil; import org.signal.core.util.logging.Log; @@ -64,8 +62,8 @@ import org.thoughtcrime.securesms.util.ExpirationUtil; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; -import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.util.UuidUtil; import java.io.IOException; @@ -77,6 +75,8 @@ import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; +import okio.ByteString; + /** * The base class for message record models that are displayed in * conversations, as opposed to models that are displayed in a thread list. @@ -235,26 +235,26 @@ public abstract class MessageRecord extends DisplayRecord { return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_a_message_from_s_couldnt_be_delivered, r.getDisplayName(context)), R.drawable.ic_error_outline_14); } else if (isThreadMergeEventType()) { try { - ThreadMergeEvent event = ThreadMergeEvent.parseFrom(Base64.decodeOrThrow(getBody())); + ThreadMergeEvent event = ThreadMergeEvent.ADAPTER.decode(Base64.decodeOrThrow(getBody())); - if (event.getPreviousE164().isEmpty()) { + if (event.previousE164.isEmpty()) { return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_another_chat_has_been_merged, r.getDisplayName(context)), R.drawable.ic_thread_merge_16); } else { - return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), PhoneNumberFormatter.prettyPrint(event.getPreviousE164())), R.drawable.ic_thread_merge_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), PhoneNumberFormatter.prettyPrint(event.previousE164)), R.drawable.ic_thread_merge_16); } - } catch (InvalidProtocolBufferException e) { + } catch (IOException e) { throw new AssertionError(e); } } else if (isSessionSwitchoverEventType()) { try { - SessionSwitchoverEvent event = SessionSwitchoverEvent.parseFrom(Base64.decodeOrThrow(getBody())); + SessionSwitchoverEvent event = SessionSwitchoverEvent.ADAPTER.decode(Base64.decodeOrThrow(getBody())); - if (event.getE164().isEmpty()) { + if (event.e164.isEmpty()) { return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16); } else { return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, PhoneNumberFormatter.prettyPrint(r.requireE164()), r.getDisplayName(context)), R.drawable.ic_update_info_16); } - } catch (InvalidProtocolBufferException e) { + } catch (IOException e) { throw new AssertionError(e); } } else if (isSmsExportType()) { @@ -282,7 +282,7 @@ public abstract class MessageRecord extends DisplayRecord { if (decryptedGroupV2Context == null) { return false; } - DecryptedGroupChange change = decryptedGroupV2Context.getChange(); + DecryptedGroupChange change = decryptedGroupV2Context.change; return selfCreatedGroup(change); } @@ -296,7 +296,7 @@ public abstract class MessageRecord extends DisplayRecord { DecryptedGroupV2Context decryptedGroupV2Context; try { byte[] decoded = Base64.decode(getBody()); - decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded); + decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded); } catch (IOException e) { Log.w(TAG, "GV2 Message update detail could not be read", e); @@ -305,28 +305,29 @@ public abstract class MessageRecord extends DisplayRecord { return decryptedGroupV2Context; } - private static boolean selfCreatedGroup(@NonNull DecryptedGroupChange change) { - return change.getRevision() == 0 && - change.getEditorServiceIdBytes().equals(SignalStore.account().requireAci().toByteString()); + private static boolean selfCreatedGroup(@Nullable DecryptedGroupChange change) { + return change != null && + change.revision == 0 && + change.editorServiceIdBytes.equals(SignalStore.account().requireAci().toByteString()); } public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull String body, @Nullable Consumer recipientClickHandler) { try { byte[] decoded = Base64.decode(body); - DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded); + DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded); GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, SignalStore.account().getServiceIds(), recipientClickHandler); - if (decryptedGroupV2Context.hasChange() && (decryptedGroupV2Context.getGroupState().getRevision() != 0 || decryptedGroupV2Context.hasPreviousGroupState())) { - return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(decryptedGroupV2Context.getPreviousGroupState(), decryptedGroupV2Context.getChange())); + if (decryptedGroupV2Context.change != null && ((decryptedGroupV2Context.groupState != null && decryptedGroupV2Context.groupState.revision != 0) || decryptedGroupV2Context.previousGroupState != null)) { + return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(decryptedGroupV2Context.previousGroupState, decryptedGroupV2Context.change)); } else { List newGroupDescriptions = new ArrayList<>(); - newGroupDescriptions.add(updateMessageProducer.describeNewGroup(decryptedGroupV2Context.getGroupState(), decryptedGroupV2Context.getChange())); + newGroupDescriptions.add(updateMessageProducer.describeNewGroup(decryptedGroupV2Context.groupState, decryptedGroupV2Context.change)); - if (decryptedGroupV2Context.getChange().hasNewTimer()) { - updateMessageProducer.describeNewTimer(decryptedGroupV2Context.getChange(), newGroupDescriptions); + if (decryptedGroupV2Context.change != null && decryptedGroupV2Context.change.newTimer != null) { + updateMessageProducer.describeNewTimer(decryptedGroupV2Context.change, newGroupDescriptions); } - if (selfCreatedGroup(decryptedGroupV2Context.getChange())) { + if (selfCreatedGroup(decryptedGroupV2Context.change)) { newGroupDescriptions.add(staticUpdateDescription(context.getString(R.string.MessageRecord_invite_friends_to_this_group), 0)); } return UpdateDescription.concatWithNewLines(newGroupDescriptions); @@ -344,11 +345,11 @@ public abstract class MessageRecord extends DisplayRecord { return null; } - DecryptedGroup groupState = decryptedGroupV2Context.getGroupState(); - boolean invited = DecryptedGroupUtil.findPendingByServiceId(groupState.getPendingMembersList(), SignalStore.account().requireAci()).isPresent(); + DecryptedGroup groupState = decryptedGroupV2Context.groupState; + boolean invited = groupState != null && DecryptedGroupUtil.findPendingByServiceId(groupState.pendingMembers, SignalStore.account().requireAci()).isPresent(); - if (decryptedGroupV2Context.hasChange()) { - ServiceId changeEditor = ServiceId.parseOrNull(decryptedGroupV2Context.getChange().getEditorServiceIdBytes()); + if (decryptedGroupV2Context.change != null) { + ServiceId changeEditor = ServiceId.parseOrNull(decryptedGroupV2Context.change.editorServiceIdBytes); if (changeEditor != null) { if (changeEditor instanceof ACI) { @@ -394,12 +395,12 @@ public abstract class MessageRecord extends DisplayRecord { private @NonNull String getProfileChangeDescription(@NonNull Context context) { try { byte[] decoded = Base64.decode(getBody()); - ProfileChangeDetails profileChangeDetails = ProfileChangeDetails.parseFrom(decoded); + ProfileChangeDetails profileChangeDetails = ProfileChangeDetails.ADAPTER.decode(decoded); - if (profileChangeDetails.hasProfileNameChange()) { + if (profileChangeDetails.profileNameChange != null) { String displayName = getFromRecipient().getDisplayName(context); - String newName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.getProfileNameChange().getNew()).toString()); - String previousName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.getProfileNameChange().getPrevious()).toString()); + String newName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.profileNameChange.newValue).toString()); + String previousName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.profileNameChange.previous).toString()); if (getFromRecipient().isSystemContact()) { return context.getString(R.string.MessageRecord_changed_their_profile_name_from_to, displayName, previousName, newName); @@ -440,7 +441,7 @@ public abstract class MessageRecord extends DisplayRecord { public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) { GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body); - List joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList()) + List joinedMembers = Stream.of(groupCallUpdateDetails.inCallUuids) .map(UuidUtil::parseOrNull) .withoutNulls() .map(ACI::from) @@ -454,15 +455,15 @@ public abstract class MessageRecord extends DisplayRecord { public boolean isGroupV2DescriptionUpdate() { DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context(); if (decryptedGroupV2Context != null) { - return decryptedGroupV2Context.hasChange() && getDecryptedGroupV2Context().getChange().hasNewDescription(); + return decryptedGroupV2Context.change != null && decryptedGroupV2Context.change.newDescription != null; } return false; } public @NonNull String getGroupV2DescriptionUpdate() { DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context(); - if (decryptedGroupV2Context != null) { - return decryptedGroupV2Context.getChange().hasNewDescription() ? decryptedGroupV2Context.getChange().getNewDescription().getValue() : ""; + if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) { + return decryptedGroupV2Context.change.newDescription != null ? decryptedGroupV2Context.change.newDescription.value_ : ""; } return ""; } @@ -474,11 +475,11 @@ public abstract class MessageRecord extends DisplayRecord { DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context(); - if (decryptedGroupV2Context != null && decryptedGroupV2Context.hasChange()) { - DecryptedGroupChange change = decryptedGroupV2Context.getChange(); + if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) { + DecryptedGroupChange change = decryptedGroupV2Context.change; ByteString serviceIdByteString = serviceId.toByteString(); - return change.getEditorServiceIdBytes().equals(serviceIdByteString) && change.getNewRequestingMembersList().stream().anyMatch(r -> r.getAciBytes().equals(serviceIdByteString)); + return change.editorServiceIdBytes.equals(serviceIdByteString) && change.newRequestingMembers.stream().anyMatch(r -> r.aciBytes.equals(serviceIdByteString)); } return false; } @@ -489,11 +490,11 @@ public abstract class MessageRecord extends DisplayRecord { public boolean isCollapsedGroupV2JoinUpdate(@Nullable ServiceId serviceId) { DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context(); - if (decryptedGroupV2Context != null && decryptedGroupV2Context.hasChange()) { - DecryptedGroupChange change = decryptedGroupV2Context.getChange(); - return change.getNewRequestingMembersCount() > 0 && - change.getDeleteRequestingMembersCount() > 0 && - (serviceId == null || change.getEditorServiceIdBytes().equals(serviceId.toByteString())); + if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) { + DecryptedGroupChange change = decryptedGroupV2Context.change; + return change.newRequestingMembers.size() > 0 && + change.deleteRequestingMembers.size() > 0 && + (serviceId == null || change.editorServiceIdBytes.equals(serviceId.toByteString())); } return false; } @@ -501,14 +502,19 @@ public abstract class MessageRecord extends DisplayRecord { public static @NonNull String createNewContextWithAppendedDeleteJoinRequest(@NonNull MessageRecord messageRecord, int revision, @NonNull ByteString id) { DecryptedGroupV2Context decryptedGroupV2Context = messageRecord.getDecryptedGroupV2Context(); - if (decryptedGroupV2Context != null && decryptedGroupV2Context.hasChange()) { - DecryptedGroupChange change = decryptedGroupV2Context.getChange(); + if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) { + DecryptedGroupChange change = decryptedGroupV2Context.change; - return Base64.encodeBytes(decryptedGroupV2Context.toBuilder() - .setChange(change.toBuilder() - .setRevision(revision) - .addDeleteRequestingMembers(id)) - .build().toByteArray()); + List deleteRequestingMembers = new ArrayList<>(change.deleteRequestingMembers); + deleteRequestingMembers.add(id); + + return Base64.encodeBytes(decryptedGroupV2Context.newBuilder() + .change(change.newBuilder() + .revision(revision) + .deleteRequestingMembers(deleteRequestingMembers) + .build()) + .build() + .encode()); } throw new AssertionError("Attempting to modify a message with no change"); @@ -553,10 +559,6 @@ public abstract class MessageRecord extends DisplayRecord { return MessageTypes.isBundleKeyExchange(type); } - public boolean isContentBundleKeyExchange() { - return MessageTypes.isContentBundleKeyExchange(type); - } - public boolean isRateLimited() { return MessageTypes.isRateLimited(type); } @@ -565,10 +567,6 @@ public abstract class MessageRecord extends DisplayRecord { return MessageTypes.isIdentityUpdate(type); } - public boolean isCorruptedKeyExchange() { - return MessageTypes.isCorruptedKeyExchange(type); - } - public boolean isBadDecryptType() { return MessageTypes.isBadDecryptType(type); } @@ -585,10 +583,6 @@ public abstract class MessageRecord extends DisplayRecord { return MessageTypes.isSmsExport(type); } - public boolean isInvalidVersionKeyExchange() { - return MessageTypes.isInvalidVersionKeyExchange(type); - } - public boolean isGroupV1MigrationEvent() { return MessageTypes.isGroupV1MigrationEvent(type); } @@ -654,8 +648,7 @@ public abstract class MessageRecord extends DisplayRecord { } public boolean equals(Object other) { - return other != null && - other instanceof MessageRecord && + return other instanceof MessageRecord && ((MessageRecord) other).getId() == getId() && ((MessageRecord) other).isMms() == isMms(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt b/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt index b0b66176ee..f4e6063edf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt @@ -156,17 +156,15 @@ class SignalSmsExportReader( private fun mapExportState(messageExportState: MessageExportState): SmsExportState { return SmsExportState( messageId = messageExportState.messageId, - startedRecipients = messageExportState.startedRecipientsList.toSet(), - completedRecipients = messageExportState.completedRecipientsList.toSet(), - startedAttachments = messageExportState.startedAttachmentsList.toSet(), - completedAttachments = messageExportState.completedAttachmentsList.toSet(), + startedRecipients = messageExportState.startedRecipients.toSet(), + completedRecipients = messageExportState.completedRecipients.toSet(), + startedAttachments = messageExportState.startedAttachments.toSet(), + completedAttachments = messageExportState.completedAttachments.toSet(), progress = messageExportState.progress.let { when (it) { MessageExportState.Progress.INIT -> SmsExportState.Progress.INIT MessageExportState.Progress.STARTED -> SmsExportState.Progress.STARTED MessageExportState.Progress.COMPLETED -> SmsExportState.Progress.COMPLETED - MessageExportState.Progress.UNRECOGNIZED -> SmsExportState.Progress.INIT - null -> SmsExportState.Progress.INIT } } ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportService.kt b/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportService.kt index 052b841c9b..1c8443a442 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportService.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportService.kt @@ -104,13 +104,13 @@ class SignalSmsExportService : SmsExportService() { override fun onMessageExportStarted(exportableMessage: ExportableMessage) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().setProgress(MessageExportState.Progress.STARTED).build() + it.newBuilder().progress(MessageExportState.Progress.STARTED).build() } } override fun onMessageExportSucceeded(exportableMessage: ExportableMessage) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().setProgress(MessageExportState.Progress.COMPLETED).build() + it.newBuilder().progress(MessageExportState.Progress.COMPLETED).build() } SignalDatabase.messages.markMessageExported(exportableMessage.getMessageId()) @@ -118,7 +118,7 @@ class SignalSmsExportService : SmsExportService() { override fun onMessageExportFailed(exportableMessage: ExportableMessage) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().setProgress(MessageExportState.Progress.INIT).build() + it.newBuilder().progress(MessageExportState.Progress.INIT).build() } SignalDatabase.messages.markMessageExportFailed(exportableMessage.getMessageId()) @@ -126,45 +126,45 @@ class SignalSmsExportService : SmsExportService() { override fun onMessageIdCreated(exportableMessage: ExportableMessage, messageId: Long) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().setMessageId(messageId).build() + it.newBuilder().messageId(messageId).build() } } override fun onAttachmentPartExportStarted(exportableMessage: ExportableMessage, part: ExportableMessage.Mms.Part) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().addStartedAttachments(part.contentId).build() + it.newBuilder().apply { startedAttachments += part.contentId }.build() } } override fun onAttachmentPartExportSucceeded(exportableMessage: ExportableMessage, part: ExportableMessage.Mms.Part) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().addCompletedAttachments(part.contentId).build() + it.newBuilder().apply { completedAttachments += part.contentId }.build() } } override fun onAttachmentPartExportFailed(exportableMessage: ExportableMessage, part: ExportableMessage.Mms.Part) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - val startedAttachments = it.startedAttachmentsList - part.contentId - it.toBuilder().clearStartedAttachments().addAllStartedAttachments(startedAttachments).build() + val startedAttachments = it.startedAttachments - part.contentId + it.newBuilder().startedAttachments(startedAttachments).build() } } override fun onRecipientExportStarted(exportableMessage: ExportableMessage, recipient: String) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().addStartedRecipients(recipient).build() + it.newBuilder().apply { startedRecipients += recipient }.build() } } override fun onRecipientExportSucceeded(exportableMessage: ExportableMessage, recipient: String) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - it.toBuilder().addCompletedRecipients(recipient).build() + it.newBuilder().apply { completedRecipients += recipient }.build() } } override fun onRecipientExportFailed(exportableMessage: ExportableMessage, recipient: String) { SignalDatabase.messages.updateMessageExportState(exportableMessage.getMessageId()) { - val startedAttachments = it.startedRecipientsList - recipient - it.toBuilder().clearStartedRecipients().addAllStartedRecipients(startedAttachments).build() + val startedAttachments = it.startedRecipients - recipient + it.newBuilder().startedRecipients(startedAttachments).build() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/fonts/TextFont.kt b/app/src/main/java/org/thoughtcrime/securesms/fonts/TextFont.kt index 3ed906587e..370859f316 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/fonts/TextFont.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/fonts/TextFont.kt @@ -24,7 +24,6 @@ enum class TextFont(@DrawableRes val icon: Int, val fallbackFamily: String, val StoryTextPost.Style.SERIF -> SERIF StoryTextPost.Style.SCRIPT -> SCRIPT StoryTextPost.Style.CONDENSED -> CONDENSED - StoryTextPost.Style.UNRECOGNIZED -> REGULAR } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/GiftBadgeModel.kt b/app/src/main/java/org/thoughtcrime/securesms/glide/GiftBadgeModel.kt index 479b44f371..2538c383e9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/GiftBadgeModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/GiftBadgeModel.kt @@ -15,7 +15,6 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.getBadge import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import java.io.InputStream -import java.lang.Exception import java.security.MessageDigest import java.util.Locale @@ -34,7 +33,7 @@ data class GiftBadgeModel(val giftBadge: GiftBadge) : Key { } override fun updateDiskCacheKey(messageDigest: MessageDigest) { - messageDigest.update(giftBadge.toByteArray()) + messageDigest.update(giftBadge.encode()) } class Fetcher( diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupId.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupId.java index 673a465f3d..b7ff181680 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupId.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupId.java @@ -3,8 +3,6 @@ package org.thoughtcrime.securesms.groups; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.ByteString; - import org.signal.core.util.DatabaseId; import org.signal.core.util.Hex; import org.signal.libsignal.protocol.kdf.HKDFv3; @@ -18,6 +16,8 @@ import org.thoughtcrime.securesms.util.Util; import java.io.IOException; import java.security.SecureRandom; +import okio.ByteString; + public abstract class GroupId implements DatabaseId { private static final String ENCODED_SIGNAL_GROUP_V1_PREFIX = "__textsecure_group__!"; diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV1.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV1.java index 3d4046c74f..cb5ccc3f46 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV1.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV1.java @@ -7,8 +7,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import com.google.protobuf.ByteString; - import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.UriAttachment; @@ -26,7 +24,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.util.MediaUtil; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; +import org.whispersystems.signalservice.internal.push.GroupContext; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -38,6 +36,8 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import okio.ByteString; + final class GroupManagerV1 { private static final String TAG = Log.tag(GroupManagerV1.class); @@ -159,13 +159,13 @@ final class GroupManagerV1 { } } - GroupContext.Builder groupContextBuilder = GroupContext.newBuilder() - .setId(ByteString.copyFrom(groupId.getDecodedId())) - .setType(GroupContext.Type.UPDATE) - .addAllMembersE164(e164Members) - .addAllMembers(uuidMembers); + GroupContext.Builder groupContextBuilder = new GroupContext.Builder() + .id(ByteString.of(groupId.getDecodedId())) + .type(GroupContext.Type.UPDATE) + .membersE164(e164Members) + .members(uuidMembers); - if (groupName != null) groupContextBuilder.setName(groupName); + if (groupName != null) groupContextBuilder.name(groupName); GroupContext groupContext = groupContextBuilder.build(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java index 3c49450bbc..2043c5c67a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java @@ -9,8 +9,6 @@ import androidx.annotation.WorkerThread; import com.annimon.stream.Collectors; import com.annimon.stream.Stream; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; import org.signal.core.util.logging.Log; import org.signal.libsignal.zkgroup.InvalidInputException; @@ -52,7 +50,6 @@ import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.ProfileUtil; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; @@ -64,9 +61,9 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException; import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException; +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.push.exceptions.AuthorizationFailedException; import org.whispersystems.signalservice.api.push.exceptions.ConflictException; @@ -91,6 +88,8 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; +import okio.ByteString; + final class GroupManagerV2 { private static final String TAG = Log.tag(GroupManagerV2.class); @@ -227,17 +226,17 @@ final class GroupManagerV2 { GroupsV2StateProcessor.StateProcessorForGroup stateProcessorForGroup = new GroupsV2StateProcessor(context).forGroup(serviceIds, groupMasterKey); DecryptedGroup latest = stateProcessorForGroup.getCurrentGroupStateFromServer(); - if (latest.getRevision() == 0) { + if (latest.revision == 0) { return latest; } - Optional selfInFullMemberList = DecryptedGroupUtil.findMemberByAci(latest.getMembersList(), selfAci); + Optional selfInFullMemberList = DecryptedGroupUtil.findMemberByAci(latest.members, selfAci); if (!selfInFullMemberList.isPresent()) { return latest; } - DecryptedGroup joinedVersion = stateProcessorForGroup.getSpecificVersionFromServer(selfInFullMemberList.get().getJoinedAtRevision()); + DecryptedGroup joinedVersion = stateProcessorForGroup.getSpecificVersionFromServer(selfInFullMemberList.get().joinedAtRevision); if (joinedVersion != null) { return joinedVersion; @@ -267,7 +266,7 @@ final class GroupManagerV2 { @WorkerThread void sendNoopGroupUpdate(@NonNull GroupMasterKey masterKey, @NonNull DecryptedGroup currentState) { - sendGroupUpdateHelper.sendGroupUpdate(masterKey, new GroupMutation(currentState, DecryptedGroupChange.newBuilder().build(), currentState), null); + sendGroupUpdateHelper.sendGroupUpdate(masterKey, new GroupMutation(currentState, new DecryptedGroupChange(), currentState), null); } @@ -308,16 +307,17 @@ final class GroupManagerV2 { groupDatabase.onAvatarUpdated(groupId, avatar != null); SignalDatabase.recipients().setProfileSharing(groupRecipient.getId(), true); - DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder(GroupChangeReconstruct.reconstructGroupChange(DecryptedGroup.newBuilder().build(), decryptedGroup)) - .setEditorServiceIdBytes(selfAci.toByteString()) - .build(); + DecryptedGroupChange groupChange = GroupChangeReconstruct.reconstructGroupChange(new DecryptedGroup(), decryptedGroup) + .newBuilder() + .editorServiceIdBytes(selfAci.toByteString()) + .build(); RecipientAndThread recipientAndThread = sendGroupUpdateHelper.sendGroupUpdate(masterKey, new GroupMutation(null, groupChange, decryptedGroup), null); return new GroupManager.GroupActionResult(recipientAndThread.groupRecipient, recipientAndThread.threadId, - decryptedGroup.getMembersCount() - 1, - getPendingMemberRecipientIds(decryptedGroup.getPendingMembersList())); + decryptedGroup.members.size() - 1, + getPendingMemberRecipientIds(decryptedGroup.pendingMembers)); } } @@ -393,17 +393,16 @@ final class GroupManagerV2 { { try { GroupChange.Actions.Builder change = title != null ? groupOperations.createModifyGroupTitle(title) - : GroupChange.Actions.newBuilder(); + : new GroupChange.Actions.Builder(); if (description != null) { - change.setModifyDescription(groupOperations.createModifyGroupDescriptionAction(description)); + change.modifyDescription(groupOperations.createModifyGroupDescriptionAction(description).build()); } if (avatarChanged) { String cdnKey = avatarBytes != null ? groupsV2Api.uploadAvatar(avatarBytes, groupSecretParams, authorization.getAuthorizationForToday(serviceIds, groupSecretParams)) : ""; - change.setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder() - .setAvatar(cdnKey)); + change.modifyAvatar(new GroupChange.Actions.ModifyAvatarAction.Builder().avatar(cdnKey).build()); } GroupManager.GroupActionResult groupActionResult = commitChangeWithConflictResolution(selfAci, change); @@ -445,7 +444,7 @@ final class GroupManagerV2 { .map(r -> Recipient.resolved(r).requireAci()) .collect(Collectors.toSet()); - return commitChangeWithConflictResolution(selfAci, groupOperations.createRefuseGroupJoinRequest(uuids, true, v2GroupProperties.getDecryptedGroup().getBannedMembersList())); + return commitChangeWithConflictResolution(selfAci, groupOperations.createRefuseGroupJoinRequest(uuids, true, v2GroupProperties.getDecryptedGroup().bannedMembers)); } @WorkerThread @@ -463,9 +462,9 @@ final class GroupManagerV2 { { GroupRecord groupRecord = groupDatabase.requireGroup(groupId); DecryptedGroup decryptedGroup = groupRecord.requireV2GroupProperties().getDecryptedGroup(); - Optional selfMember = DecryptedGroupUtil.findMemberByAci(decryptedGroup.getMembersList(), selfAci); - Optional aciPendingMember = DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.getPendingMembersList(), selfAci); - Optional pniPendingMember = DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.getPendingMembersList(), selfPni); + Optional selfMember = DecryptedGroupUtil.findMemberByAci(decryptedGroup.members, selfAci); + Optional aciPendingMember = DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembers, selfAci); + Optional pniPendingMember = DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembers, selfPni); Optional selfPendingMember = Optional.empty(); ServiceId serviceId = selfAci; @@ -478,7 +477,7 @@ final class GroupManagerV2 { if (selfPendingMember.isPresent()) { try { - revokeInvites(serviceId, Collections.singleton(new UuidCiphertext(selfPendingMember.get().getServiceIdCipherText().toByteArray())), false); + revokeInvites(serviceId, Collections.singleton(new UuidCiphertext(selfPendingMember.get().serviceIdCipherText.toByteArray())), false); } catch (InvalidInputException e) { throw new AssertionError(e); } @@ -496,7 +495,7 @@ final class GroupManagerV2 { return commitChangeWithConflictResolution(selfAci, groupOperations.createRemoveMembersChange(Collections.singleton(aci), ban, - ban ? v2GroupProperties.getDecryptedGroup().getBannedMembersList() + ban ? v2GroupProperties.getDecryptedGroup().bannedMembers : Collections.emptyList()), allowWhenBlocked, sendToMembers); @@ -518,14 +517,14 @@ final class GroupManagerV2 { { ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey(); DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup(); - Optional selfInGroup = DecryptedGroupUtil.findMemberByAci(group.getMembersList(), selfAci); + Optional selfInGroup = DecryptedGroupUtil.findMemberByAci(group.members, selfAci); if (!selfInGroup.isPresent()) { Log.w(TAG, "Self not in group " + groupId); return null; } - if (Arrays.equals(profileKey.serialize(), selfInGroup.get().getProfileKey().toByteArray())) { + if (Arrays.equals(profileKey.serialize(), selfInGroup.get().profileKey.toByteArray())) { Log.i(TAG, "Own Profile Key is already up to date in group " + groupId); return null; } else { @@ -548,15 +547,15 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException { DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup(); - Optional selfInGroup = DecryptedGroupUtil.findMemberByAci(group.getMembersList(), selfAci); + Optional selfInGroup = DecryptedGroupUtil.findMemberByAci(group.members, selfAci); if (selfInGroup.isPresent()) { Log.w(TAG, "Self already in group"); return null; } - Optional aciInPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfAci); - Optional pniInPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfPni); + Optional aciInPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfAci); + Optional pniInPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfPni); GroupCandidate groupCandidate = groupCandidateHelper.recipientIdToCandidate(Recipient.self().getId()); @@ -579,9 +578,9 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException { ByteString serviceIdByteString = serviceId.toByteString(); - boolean rejectJoinRequest = v2GroupProperties.getDecryptedGroup().getRequestingMembersList().stream().anyMatch(m -> m.getAciBytes().equals(serviceIdByteString)); + boolean rejectJoinRequest = v2GroupProperties.getDecryptedGroup().requestingMembers.stream().anyMatch(m -> m.aciBytes.equals(serviceIdByteString)); - return commitChangeWithConflictResolution(selfAci, groupOperations.createBanServiceIdsChange(Collections.singleton(serviceId), rejectJoinRequest, v2GroupProperties.getDecryptedGroup().getBannedMembersList())); + return commitChangeWithConflictResolution(selfAci, groupOperations.createBanServiceIdsChange(Collections.singleton(serviceId), rejectJoinRequest, v2GroupProperties.getDecryptedGroup().bannedMembers)); } public GroupManager.GroupActionResult unban(Set serviceIds) @@ -615,7 +614,7 @@ final class GroupManagerV2 { if (state != GroupManager.GroupLinkState.DISABLED) { DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup(); - if (group.getInviteLinkPassword().isEmpty()) { + if (group.inviteLinkPassword.size() == 0) { Log.d(TAG, "First time enabling group links for group and password empty, generating"); change = groupOperations.createModifyGroupLinkPasswordAndRightsChange(GroupLinkPassword.createNew().serialize(), access); } @@ -650,13 +649,13 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException { boolean refetchedAddMemberCredentials = false; - change.setSourceServiceId(UuidUtil.toByteString(authServiceId.getRawUuid())); + change.sourceServiceId(UuidUtil.toByteString(authServiceId.getRawUuid())); for (int attempt = 0; attempt < 5; attempt++) { try { return commitChange(change, allowWhenBlocked, sendToMembers); } catch (GroupPatchNotAcceptedException e) { - if (change.getAddMembersCount() > 0 && !refetchedAddMemberCredentials) { + if (change.addMembers.size() > 0 && !refetchedAddMemberCredentials) { refetchedAddMemberCredentials = true; change = refetchAddMemberCredentials(change); } else { @@ -692,7 +691,7 @@ final class GroupManagerV2 { } if (groupUpdateResult.getGroupState() != GroupsV2StateProcessor.GroupState.GROUP_UPDATED) { - int serverRevision = groupUpdateResult.getLatestServer().getRevision(); + int serverRevision = groupUpdateResult.getLatestServer().revision; int localRevision = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getGroupRevision(); int revisionDelta = serverRevision - localRevision; Log.w(TAG, String.format(Locale.US, "Server is ahead by %d revisions", revisionDelta)); @@ -713,7 +712,7 @@ final class GroupManagerV2 { private GroupChange.Actions.Builder refetchAddMemberCredentials(@NonNull GroupChange.Actions.Builder change) { try { - List ids = groupOperations.decryptAddMembers(change.getAddMembersList()) + List ids = groupOperations.decryptAddMembers(change.addMembers) .stream() .map(RecipientId::from) .collect(java.util.stream.Collectors.toList()); @@ -738,10 +737,10 @@ final class GroupManagerV2 { final GroupRecord groupRecord = groupDatabase.requireGroup(groupId); final GroupTable.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties(); final int nextRevision = v2GroupProperties.getGroupRevision() + 1; - final GroupChange.Actions changeActions = change.setRevision(nextRevision).build(); - final DecryptedGroupChange decryptedChange; - final DecryptedGroup decryptedGroupState; - final DecryptedGroup previousGroupState; + final GroupChange.Actions changeActions = change.revision(nextRevision).build(); + final DecryptedGroupChange decryptedChange; + final DecryptedGroup decryptedGroupState; + final DecryptedGroup previousGroupState; if (!allowWhenBlocked && Recipient.externalGroupExact(groupId).isBlocked()) { throw new GroupChangeFailedException("Group is blocked."); @@ -763,8 +762,8 @@ final class GroupManagerV2 { GroupMutation groupMutation = new GroupMutation(previousGroupState, decryptedChange, decryptedGroupState); RecipientAndThread recipientAndThread = sendGroupUpdateHelper.sendGroupUpdate(groupMasterKey, groupMutation, signedGroupChange, sendToMembers); - int newMembersCount = decryptedChange.getNewMembersCount(); - List newPendingMembers = getPendingMemberRecipientIds(decryptedChange.getNewPendingMembersList()); + int newMembersCount = decryptedChange.newMembers.size(); + List newPendingMembers = getPendingMemberRecipientIds(decryptedChange.newPendingMembers); return new GroupManager.GroupActionResult(recipientAndThread.groupRecipient, recipientAndThread.threadId, newMembersCount, newPendingMembers); } @@ -826,9 +825,9 @@ final class GroupManagerV2 { GroupsV2Operations.GroupOperations groupOperations = groupsV2Operations.forGroup(GroupSecretParams.deriveFromMasterKey(groupMasterKey)); try { - return groupOperations.decryptChange(GroupChange.parseFrom(signedGroupChange), true) + return groupOperations.decryptChange(GroupChange.ADAPTER.decode(signedGroupChange), true) .orElse(null); - } catch (VerificationFailedException | InvalidGroupStateException | InvalidProtocolBufferException e) { + } catch (VerificationFailedException | InvalidGroupStateException | IOException e) { Log.w(TAG, "Unable to verify supplied group change", e); } } @@ -912,7 +911,7 @@ final class GroupManagerV2 { @Nullable byte[] avatar) throws GroupChangeFailedException, IOException, MembershipNotSuitableForV2Exception, GroupLinkNotActiveException { - boolean requestToJoin = joinInfo.getAddFromInviteLink() == AccessControl.AccessRequired.ADMINISTRATOR; + boolean requestToJoin = joinInfo.addFromInviteLink == AccessControl.AccessRequired.ADMINISTRATOR; boolean alreadyAMember = false; if (requestToJoin) { @@ -924,7 +923,7 @@ final class GroupManagerV2 { GroupChange signedGroupChange = null; DecryptedGroupChange decryptedChange = null; try { - signedGroupChange = joinGroupOnServer(requestToJoin, joinInfo.getRevision()); + signedGroupChange = joinGroupOnServer(requestToJoin, joinInfo.revision); if (requestToJoin) { Log.i(TAG, String.format("Successfully requested to join %s on server", groupId)); @@ -954,7 +953,7 @@ final class GroupManagerV2 { if (decryptedChange != null) { try { groupsV2StateProcessor.forGroup(SignalStore.account().getServiceIds(), groupMasterKey) - .updateLocalGroupToRevision(decryptedChange.getRevision(), System.currentTimeMillis(), decryptedChange); + .updateLocalGroupToRevision(decryptedChange.revision, System.currentTimeMillis(), decryptedChange); } catch (GroupNotAMemberException e) { Log.w(TAG, "Unable to apply join change to existing group", e); } @@ -968,7 +967,7 @@ final class GroupManagerV2 { if (decryptedChange != null) { try { groupsV2StateProcessor.forGroup(SignalStore.account().getServiceIds(), groupMasterKey) - .updateLocalGroupToRevision(decryptedChange.getRevision(), System.currentTimeMillis(), decryptedChange); + .updateLocalGroupToRevision(decryptedChange.revision, System.currentTimeMillis(), decryptedChange); } catch (GroupNotAMemberException e) { Log.w(TAG, "Unable to apply join change to existing group", e); } @@ -1017,7 +1016,7 @@ final class GroupManagerV2 { { try { new GroupsV2StateProcessor(context).forGroup(serviceIds, groupMasterKey) - .updateLocalGroupToRevision(decryptedChange.getRevision(), + .updateLocalGroupToRevision(decryptedChange.revision, System.currentTimeMillis(), decryptedChange); @@ -1050,7 +1049,7 @@ final class GroupManagerV2 { try { //noinspection OptionalGetWithoutIsPresent return groupOperations.decryptChange(signedGroupChange, false).get(); - } catch (VerificationFailedException | InvalidGroupStateException | InvalidProtocolBufferException e) { + } catch (VerificationFailedException | InvalidGroupStateException | IOException e) { Log.w(TAG, e); throw new GroupChangeFailedException(e); } @@ -1064,23 +1063,25 @@ final class GroupManagerV2 { * update message. */ private DecryptedGroup createPlaceholderGroup(@NonNull DecryptedGroupJoinInfo joinInfo, boolean requestToJoin) { - DecryptedGroup.Builder group = DecryptedGroup.newBuilder() - .setTitle(joinInfo.getTitle()) - .setAvatar(joinInfo.getAvatar()) - .setRevision(GroupsV2StateProcessor.PLACEHOLDER_REVISION); + DecryptedGroup.Builder group = new DecryptedGroup.Builder() + .title(joinInfo.title) + .avatar(joinInfo.avatar) + .revision(GroupsV2StateProcessor.PLACEHOLDER_REVISION); Recipient self = Recipient.self(); ByteString selfAciBytes = selfAci.toByteString(); - ByteString profileKey = ByteString.copyFrom(Objects.requireNonNull(self.getProfileKey())); + ByteString profileKey = ByteString.of(Objects.requireNonNull(self.getProfileKey())); if (requestToJoin) { - group.addRequestingMembers(DecryptedRequestingMember.newBuilder() - .setAciBytes(selfAciBytes) - .setProfileKey(profileKey)); + group.requestingMembers(Collections.singletonList(new DecryptedRequestingMember.Builder() + .aciBytes(selfAciBytes) + .profileKey(profileKey) + .build())); } else { - group.addMembers(DecryptedMember.newBuilder() - .setAciBytes(selfAciBytes) - .setProfileKey(profileKey)); + group.members(Collections.singletonList(new DecryptedMember.Builder() + .aciBytes(selfAciBytes) + .profileKey(profileKey) + .build())); } return group.build(); @@ -1104,7 +1105,7 @@ final class GroupManagerV2 { GroupChange.Actions.Builder change = requestToJoin ? groupOperations.createGroupJoinRequest(expiringProfileKeyCredential) : groupOperations.createGroupJoinDirect(expiringProfileKeyCredential); - change.setSourceServiceId(selfAci.toByteString()); + change.sourceServiceId(selfAci.toByteString()); return commitJoinChangeWithConflictResolution(currentRevision, change); } @@ -1114,13 +1115,13 @@ final class GroupManagerV2 { { for (int attempt = 0; attempt < 5; attempt++) { try { - GroupChange.Actions changeActions = change.setRevision(currentRevision + 1) + GroupChange.Actions changeActions = change.revision(currentRevision + 1) .build(); - Log.i(TAG, "Trying to join group at V" + changeActions.getRevision()); + Log.i(TAG, "Trying to join group at V" + changeActions.revision); GroupChange signedGroupChange = commitJoinToServer(changeActions); - Log.i(TAG, "Successfully joined group at V" + changeActions.getRevision()); + Log.i(TAG, "Successfully joined group at V" + changeActions.revision); return signedGroupChange; } catch (GroupPatchNotAcceptedException e) { Log.w(TAG, "Patch not accepted", e); @@ -1162,7 +1163,7 @@ final class GroupManagerV2 { throws IOException, GroupLinkNotActiveException, GroupChangeFailedException { try { - int currentRevision = getGroupJoinInfoFromServer(groupMasterKey, password).getRevision(); + int currentRevision = getGroupJoinInfoFromServer(groupMasterKey, password).revision; Log.i(TAG, "Server now on V" + currentRevision); @@ -1176,7 +1177,7 @@ final class GroupManagerV2 { throws IOException, GroupLinkNotActiveException, GroupChangeFailedException { try { - boolean pendingAdminApproval = getGroupJoinInfoFromServer(groupMasterKey, password).getPendingAdminApproval(); + boolean pendingAdminApproval = getGroupJoinInfoFromServer(groupMasterKey, password).pendingAdminApproval; if (pendingAdminApproval) { Log.i(TAG, "User is already pending admin approval"); @@ -1220,7 +1221,7 @@ final class GroupManagerV2 { DecryptedGroupChange decryptedChange = groupOperations.decryptChange(signedGroupChange, false).get(); DecryptedGroup newGroup = DecryptedGroupUtil.applyWithoutRevisionCheck(decryptedGroup, decryptedChange); - groupDatabase.update(groupId, resetRevision(newGroup, decryptedGroup.getRevision())); + groupDatabase.update(groupId, resetRevision(newGroup, decryptedGroup.revision)); sendGroupUpdateHelper.sendGroupUpdate(groupMasterKey, new GroupMutation(decryptedGroup, decryptedChange, newGroup), signedGroupChange, false); } catch (VerificationFailedException | InvalidGroupStateException | NotAbleToApplyGroupV2ChangeException e) { @@ -1229,9 +1230,9 @@ final class GroupManagerV2 { } private DecryptedGroup resetRevision(DecryptedGroup newGroup, int revision) { - return DecryptedGroup.newBuilder(newGroup) - .setRevision(revision) - .build(); + return newGroup.newBuilder() + .revision(revision) + .build(); } private @NonNull GroupChange commitCancelChangeWithConflictResolution(@NonNull GroupChange.Actions.Builder change) @@ -1241,13 +1242,13 @@ final class GroupManagerV2 { for (int attempt = 0; attempt < 5; attempt++) { try { - GroupChange.Actions changeActions = change.setRevision(currentRevision + 1) + GroupChange.Actions changeActions = change.revision(currentRevision + 1) .build(); - Log.i(TAG, "Trying to cancel request group at V" + changeActions.getRevision()); + Log.i(TAG, "Trying to cancel request group at V" + changeActions.revision); GroupChange signedGroupChange = commitJoinToServer(changeActions); - Log.i(TAG, "Successfully cancelled group join at V" + changeActions.getRevision()); + Log.i(TAG, "Successfully cancelled group join at V" + changeActions.revision); return signedGroupChange; } catch (GroupPatchNotAcceptedException e) { throw new GroupChangeFailedException(e); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java index 19ff215852..5b099dff15 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java @@ -1,13 +1,9 @@ package org.thoughtcrime.securesms.groups; -import android.content.Context; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import com.google.protobuf.ByteString; - import org.signal.libsignal.zkgroup.groups.GroupMasterKey; import org.signal.storageservice.protos.groups.GroupChange; import org.signal.storageservice.protos.groups.local.DecryptedGroup; @@ -20,11 +16,11 @@ import org.thoughtcrime.securesms.recipients.RecipientId; import org.whispersystems.signalservice.api.groupsv2.PartialDecryptedGroup; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; -import org.whispersystems.signalservice.api.util.UuidUtil; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.GroupContextV2; import java.util.List; -import java.util.UUID; + +import okio.ByteString; public final class GroupProtoUtil { @@ -36,12 +32,12 @@ public final class GroupProtoUtil { { ByteString bytes = self.toByteString(); for (DecryptedMember decryptedMember : partialDecryptedGroup.getMembersList()) { - if (decryptedMember.getAciBytes().equals(bytes)) { - return decryptedMember.getJoinedAtRevision(); + if (decryptedMember.aciBytes.equals(bytes)) { + return decryptedMember.joinedAtRevision; } } for (DecryptedPendingMember decryptedMember : partialDecryptedGroup.getPendingMembersList()) { - if (decryptedMember.getServiceIdBytes().equals(bytes)) { + if (decryptedMember.serviceIdBytes.equals(bytes)) { // Assume latest, we don't have any information about when pending members were invited return partialDecryptedGroup.getRevision(); } @@ -53,27 +49,27 @@ public final class GroupProtoUtil { @NonNull GroupMutation groupMutation, @Nullable GroupChange signedServerChange) { - DecryptedGroupChange plainGroupChange = groupMutation.getGroupChange(); - DecryptedGroup decryptedGroup = groupMutation.getNewGroupState(); - int revision = plainGroupChange != null ? plainGroupChange.getRevision() : decryptedGroup.getRevision(); - SignalServiceProtos.GroupContextV2.Builder contextBuilder = SignalServiceProtos.GroupContextV2.newBuilder() - .setMasterKey(ByteString.copyFrom(masterKey.serialize())) - .setRevision(revision); + DecryptedGroupChange plainGroupChange = groupMutation.getGroupChange(); + DecryptedGroup decryptedGroup = groupMutation.getNewGroupState(); + int revision = plainGroupChange != null ? plainGroupChange.revision : decryptedGroup.revision; + GroupContextV2.Builder contextBuilder = new GroupContextV2.Builder() + .masterKey(ByteString.of(masterKey.serialize())) + .revision(revision); if (signedServerChange != null) { - contextBuilder.setGroupChange(signedServerChange.toByteString()); + contextBuilder.groupChange(signedServerChange.encodeByteString()); } - DecryptedGroupV2Context.Builder builder = DecryptedGroupV2Context.newBuilder() - .setContext(contextBuilder.build()) - .setGroupState(decryptedGroup); + DecryptedGroupV2Context.Builder builder = new DecryptedGroupV2Context.Builder() + .context(contextBuilder.build()) + .groupState(decryptedGroup); if (groupMutation.getPreviousGroupState() != null) { - builder.setPreviousGroupState(groupMutation.getPreviousGroupState()); + builder.previousGroupState(groupMutation.getPreviousGroupState()); } if (plainGroupChange != null) { - builder.setChange(plainGroupChange); + builder.change(plainGroupChange); } return builder.build(); @@ -81,7 +77,7 @@ public final class GroupProtoUtil { @WorkerThread public static Recipient pendingMemberToRecipient(@NonNull DecryptedPendingMember pendingMember) { - return pendingMemberServiceIdToRecipient(pendingMember.getServiceIdBytes()); + return pendingMemberServiceIdToRecipient(pendingMember.serviceIdBytes); } @WorkerThread @@ -110,7 +106,7 @@ public final class GroupProtoUtil { ByteString aciBytes = aci.toByteString(); for (DecryptedMember member : membersList) { - if (aciBytes.equals(member.getAciBytes())) { + if (aciBytes.equals(member.aciBytes)) { return true; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java index b993f04d69..1abaa3b111 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java @@ -173,10 +173,10 @@ public final class GroupsV1MigrationUtil { return null; } - Log.i(TAG, "[Local] Migrating group over to the version we were added to: V" + decryptedGroup.getRevision()); + Log.i(TAG, "[Local] Migrating group over to the version we were added to: V" + decryptedGroup.revision); SignalDatabase.groups().migrateToV2(threadId, gv1Id, decryptedGroup); - Log.i(TAG, "[Local] Applying all changes since V" + decryptedGroup.getRevision()); + Log.i(TAG, "[Local] Applying all changes since V" + decryptedGroup.revision); try { GroupManager.updateGroupFromServer(context, gv1Id.deriveV2MigrationMasterKey(), LATEST, System.currentTimeMillis(), null); } catch (GroupChangeBusyException | GroupNotAMemberException e) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java b/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java index 7db502f5ea..c3b195e81d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java @@ -34,7 +34,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; -import java.util.UUID; public final class LiveGroup { @@ -68,9 +67,9 @@ public final class LiveGroup { LiveData v2Properties = Transformations.map(this.groupRecord, GroupRecord::requireV2GroupProperties); this.groupLink = Transformations.map(v2Properties, g -> { DecryptedGroup group = g.getDecryptedGroup(); - AccessControl.AccessRequired addFromInviteLink = group.getAccessControl().getAddFromInviteLink(); + AccessControl.AccessRequired addFromInviteLink = group.accessControl.addFromInviteLink; - if (group.getInviteLinkPassword().isEmpty()) { + if (group.inviteLinkPassword.size() == 0) { return GroupLinkUrlAndStatus.NONE; } @@ -107,11 +106,11 @@ public final class LiveGroup { } boolean selfAdmin = g.isAdmin(Recipient.self()); - List requestingMembersList = g.requireV2GroupProperties().getDecryptedGroup().getRequestingMembersList(); + List requestingMembersList = g.requireV2GroupProperties().getDecryptedGroup().requestingMembers; return Stream.of(requestingMembersList) .map(requestingMember -> { - Recipient recipient = Recipient.externalPush(ServiceId.parseOrThrow(requestingMember.getAciBytes())); + Recipient recipient = Recipient.externalPush(ServiceId.parseOrThrow(requestingMember.aciBytes)); return new GroupMemberEntry.RequestingMember(recipient, selfAdmin); }) .toList(); @@ -157,7 +156,7 @@ public final class LiveGroup { } public LiveData getPendingMemberCount() { - return Transformations.map(groupRecord, g -> g.isV2Group() ? g.requireV2GroupProperties().getDecryptedGroup().getPendingMembersCount() : 0); + return Transformations.map(groupRecord, g -> g.isV2Group() ? g.requireV2GroupProperties().getDecryptedGroup().pendingMembers.size() : 0); } public LiveData getPendingAndRequestingMemberCount() { @@ -165,7 +164,7 @@ public final class LiveGroup { if (g.isV2Group()) { DecryptedGroup decryptedGroup = g.requireV2GroupProperties().getDecryptedGroup(); - return decryptedGroup.getPendingMembersCount() + decryptedGroup.getRequestingMembersCount(); + return decryptedGroup.pendingMembers.size() + decryptedGroup.requestingMembers.size(); } return 0; }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java index 3e791d06f9..81cd8b812c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java @@ -7,7 +7,6 @@ import androidx.annotation.WorkerThread; import androidx.core.util.Consumer; import com.annimon.stream.Stream; -import com.google.protobuf.ByteString; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; @@ -30,6 +29,8 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.Executor; +import okio.ByteString; + /** * Repository for modifying the pending members on a single group. */ @@ -49,17 +50,17 @@ final class PendingMemberInvitesRepository { public void getInvitees(@NonNull Consumer onInviteesLoaded) { executor.execute(() -> { - GroupTable groupDatabase = SignalDatabase.groups(); - GroupTable.V2GroupProperties v2GroupProperties = groupDatabase.getGroup(groupId).get().requireV2GroupProperties(); - DecryptedGroup decryptedGroup = v2GroupProperties.getDecryptedGroup(); - List pendingMembersList = decryptedGroup.getPendingMembersList(); + GroupTable groupDatabase = SignalDatabase.groups(); + GroupTable.V2GroupProperties v2GroupProperties = groupDatabase.getGroup(groupId).get().requireV2GroupProperties(); + DecryptedGroup decryptedGroup = v2GroupProperties.getDecryptedGroup(); + List pendingMembersList = decryptedGroup.pendingMembers; List byMe = new ArrayList<>(pendingMembersList.size()); List byOthers = new ArrayList<>(pendingMembersList.size()); ByteString self = SignalStore.account().requireAci().toByteString(); boolean selfIsAdmin = v2GroupProperties.isAdmin(Recipient.self()); Stream.of(pendingMembersList) - .groupBy(DecryptedPendingMember::getAddedByAci) + .groupBy(m -> m.addedByAci) .forEach(g -> { ByteString inviterAci = g.getKey(); @@ -69,7 +70,7 @@ final class PendingMemberInvitesRepository { for (DecryptedPendingMember pendingMember : invitedMembers) { try { Recipient invitee = GroupProtoUtil.pendingMemberToRecipient(pendingMember); - UuidCiphertext uuidCipherText = new UuidCiphertext(pendingMember.getServiceIdCipherText().toByteArray()); + UuidCiphertext uuidCipherText = new UuidCiphertext(pendingMember.serviceIdCipherText.toByteArray()); byMe.add(new SinglePendingMemberInvitedByYou(invitee, uuidCipherText)); } catch (InvalidInputException e) { @@ -82,7 +83,7 @@ final class PendingMemberInvitesRepository { for (DecryptedPendingMember pendingMember : invitedMembers) { try { - uuidCipherTexts.add(new UuidCiphertext(pendingMember.getServiceIdCipherText().toByteArray())); + uuidCipherTexts.add(new UuidCiphertext(pendingMember.serviceIdCipherText.toByteArray())); } catch (InvalidInputException e) { Log.w(TAG, e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupDetails.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupDetails.java index 85dd1af442..779b6e8933 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupDetails.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupDetails.java @@ -18,11 +18,11 @@ public final class GroupDetails { } public @NonNull String getGroupName() { - return joinInfo.getTitle(); + return joinInfo.title; } public @NonNull String getGroupDescription() { - return joinInfo.getDescription(); + return joinInfo.description; } public @Nullable byte[] getAvatarBytes() { @@ -34,10 +34,10 @@ public final class GroupDetails { } public int getGroupMembershipCount() { - return joinInfo.getMemberCount(); + return joinInfo.memberCount; } public boolean joinRequiresAdminApproval() { - return joinInfo.getAddFromInviteLink() == AccessControl.AccessRequired.ADMINISTRATOR; + return joinInfo.addFromInviteLink == AccessControl.AccessRequired.ADMINISTRATOR; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinRepository.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinRepository.java index d3761d12e0..c135f1d0b1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinRepository.java @@ -86,7 +86,7 @@ final class GroupJoinRepository { private @Nullable byte[] tryGetAvatarBytes(@NonNull DecryptedGroupJoinInfo joinInfo) { try { - return AvatarGroupsV2DownloadJob.downloadGroupAvatarBytes(context, groupInviteLinkUrl.getGroupMasterKey(), joinInfo.getAvatar()); + return AvatarGroupsV2DownloadJob.downloadGroupAvatarBytes(context, groupInviteLinkUrl.getGroupMasterKey(), joinInfo.avatar); } catch (IOException e) { Log.w(TAG, "Failed to get group avatar", e); return null; diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java index 8332a96144..325239f176 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java @@ -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.groups.GroupMasterKey; import org.signal.storageservice.protos.groups.GroupInviteLink; @@ -15,6 +13,8 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import okio.ByteString; + public final class GroupInviteLinkUrl { private static final String GROUP_URL_HOST = "signal.group"; @@ -27,7 +27,7 @@ public final class GroupInviteLinkUrl { public static GroupInviteLinkUrl forGroup(@NonNull GroupMasterKey groupMasterKey, @NonNull DecryptedGroup group) { - return new GroupInviteLinkUrl(groupMasterKey, GroupLinkPassword.fromBytes(group.getInviteLinkPassword().toByteArray())); + return new GroupInviteLinkUrl(groupMasterKey, GroupLinkPassword.fromBytes(group.inviteLinkPassword.toByteArray())); } public static boolean isGroupLink(@NonNull String urlString) { @@ -59,20 +59,19 @@ public final class GroupInviteLinkUrl { } byte[] bytes = Base64UrlSafe.decodePaddingAgnostic(encoding); - GroupInviteLink groupInviteLink = GroupInviteLink.parseFrom(bytes); + GroupInviteLink groupInviteLink = GroupInviteLink.ADAPTER.decode(bytes); //noinspection SwitchStatementWithTooFewBranches - switch (groupInviteLink.getContentsCase()) { - case V1CONTENTS: { - GroupInviteLink.GroupInviteLinkContentsV1 groupInviteLinkContentsV1 = groupInviteLink.getV1Contents(); - GroupMasterKey groupMasterKey = new GroupMasterKey(groupInviteLinkContentsV1.getGroupMasterKey().toByteArray()); - GroupLinkPassword password = GroupLinkPassword.fromBytes(groupInviteLinkContentsV1.getInviteLinkPassword().toByteArray()); + if (groupInviteLink.v1Contents != null) { + GroupInviteLink.GroupInviteLinkContentsV1 groupInviteLinkContentsV1 = groupInviteLink.v1Contents; + GroupMasterKey groupMasterKey = new GroupMasterKey(groupInviteLinkContentsV1.groupMasterKey.toByteArray()); + GroupLinkPassword password = GroupLinkPassword.fromBytes(groupInviteLinkContentsV1.inviteLinkPassword.toByteArray()); - return new GroupInviteLinkUrl(groupMasterKey, password); - } - default: throw new UnknownGroupLinkVersionException("Url contains no known group link content"); + return new GroupInviteLinkUrl(groupMasterKey, password); + } else { + throw new UnknownGroupLinkVersionException("Url contains no known group link content"); } - } catch (InvalidInputException | IOException e) { + } catch (InvalidInputException | IllegalStateException | IOException e) { throw new InvalidGroupLinkException(e); } } @@ -106,13 +105,14 @@ public final class GroupInviteLinkUrl { } protected static @NonNull String createUrl(@NonNull GroupMasterKey groupMasterKey, @NonNull GroupLinkPassword password) { - GroupInviteLink groupInviteLink = GroupInviteLink.newBuilder() - .setV1Contents(GroupInviteLink.GroupInviteLinkContentsV1.newBuilder() - .setGroupMasterKey(ByteString.copyFrom(groupMasterKey.serialize())) - .setInviteLinkPassword(ByteString.copyFrom(password.serialize()))) - .build(); + GroupInviteLink groupInviteLink = new GroupInviteLink.Builder() + .v1Contents(new GroupInviteLink.GroupInviteLinkContentsV1.Builder() + .groupMasterKey(ByteString.of(groupMasterKey.serialize())) + .inviteLinkPassword(ByteString.of(password.serialize())) + .build()) + .build(); - String encoding = Base64UrlSafe.encodeBytesWithoutPadding(groupInviteLink.toByteArray()); + String encoding = Base64UrlSafe.encodeBytesWithoutPadding(groupInviteLink.encode()); return GROUP_URL_PREFIX + encoding; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java index 30bcc92414..7bc24243fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java @@ -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.core.util.logging.Log; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.profiles.ProfileKey; @@ -12,13 +10,13 @@ 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.DecryptedRequestingMember; -import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; -import org.whispersystems.signalservice.api.util.UuidUtil; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.LinkedHashMap; import java.util.Map; -import java.util.UUID; + +import okio.ByteString; /** * Collects profile keys from group states. @@ -42,25 +40,29 @@ public final class ProfileKeySet { * authoritative. */ public void addKeysFromGroupChange(@NonNull DecryptedGroupChange change) { - ServiceId editor = ServiceId.parseOrNull(change.getEditorServiceIdBytes()); + ServiceId editor = ServiceId.parseOrNull(change.editorServiceIdBytes); - for (DecryptedMember member : change.getNewMembersList()) { + for (DecryptedMember member : change.newMembers) { addMemberKey(member, editor); } - for (DecryptedMember member : change.getPromotePendingMembersList()) { + for (DecryptedMember member : change.promotePendingMembers) { addMemberKey(member, editor); } - for (DecryptedMember member : change.getModifiedProfileKeysList()) { + for (DecryptedMember member : change.modifiedProfileKeys) { addMemberKey(member, editor); } - for (DecryptedRequestingMember member : change.getNewRequestingMembersList()) { - addMemberKey(editor, member.getAciBytes(), member.getProfileKey()); + for (DecryptedRequestingMember member : change.newRequestingMembers) { + addMemberKey(editor, member.aciBytes, member.profileKey); } - for (DecryptedMember member : change.getPromotePendingPniAciMembersList()) { + for (DecryptedMember member : change.promotePendingPniAciMembers) { + addMemberKey(member, editor); + } + + for (DecryptedMember member : change.promotePendingPniAciMembers) { addMemberKey(member, editor); } } @@ -73,13 +75,13 @@ public final class ProfileKeySet { * gathered from a group state can only be used to fill in gaps in knowledge. */ public void addKeysFromGroupState(@NonNull DecryptedGroup group) { - for (DecryptedMember member : group.getMembersList()) { + for (DecryptedMember member : group.members) { addMemberKey(member, null); } } private void addMemberKey(@NonNull DecryptedMember member, @Nullable ServiceId changeSource) { - addMemberKey(changeSource, member.getAciBytes(), member.getProfileKey()); + addMemberKey(changeSource, member.aciBytes, member.profileKey); } private void addMemberKey(@Nullable ServiceId changeSource, diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupState.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupState.java index 149d7562dc..800775a088 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupState.java @@ -43,7 +43,7 @@ final class GlobalGroupState { int getEarliestRevisionNumber() { if (localState != null) { - return localState.getRevision(); + return localState.revision; } else { if (serverHistory.isEmpty()) { throw new AssertionError(); @@ -57,7 +57,7 @@ final class GlobalGroupState { if (localState == null) { throw new AssertionError(); } - return localState.getRevision(); + return localState.revision; } return serverHistory.get(serverHistory.size() - 1).getRevision(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapper.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapper.java index ac086fb8cb..874ddea4fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapper.java @@ -70,7 +70,7 @@ final class GroupStateMapper { final int from = Math.max(0, inputState.getEarliestRevisionNumber()); final int to = Math.min(inputState.getLatestRevisionNumber(), maximumRevisionToApply); - if (current != null && current.getRevision() == PLACEHOLDER_REVISION) { + if (current != null && current.revision == PLACEHOLDER_REVISION) { Log.i(TAG, "Ignoring place holder group state"); } else { stateChain.push(current, null); @@ -83,11 +83,11 @@ final class GroupStateMapper { continue; } - if (stateChain.getLatestState() == null && entry.getGroup() != null && current != null && current.getRevision() == PLACEHOLDER_REVISION) { - DecryptedGroup previousState = DecryptedGroup.newBuilder(entry.getGroup()) - .setTitle(current.getTitle()) - .setAvatar(current.getAvatar()) - .build(); + if (stateChain.getLatestState() == null && entry.getGroup() != null && current != null && current.revision == PLACEHOLDER_REVISION) { + DecryptedGroup previousState = entry.getGroup().newBuilder() + .title(current.title) + .avatar(current.avatar) + .build(); stateChain.push(previousState, null); } @@ -135,12 +135,12 @@ final class GroupStateMapper { try { return DecryptedGroupUtil.applyWithoutRevisionCheck(group, change); } catch (NotAbleToApplyGroupV2ChangeException e) { - Log.w(TAG, "Unable to apply V" + change.getRevision(), e); + Log.w(TAG, "Unable to apply V" + change.revision, e); return null; } }, (groupB, groupA) -> GroupChangeReconstruct.reconstructGroupChange(groupA, groupB), - (groupA, groupB) -> groupA.getRevision() == groupB.getRevision() && DecryptedGroupUtil.changeIsEmpty(GroupChangeReconstruct.reconstructGroupChange(groupA, groupB)) + (groupA, groupB) -> groupA.revision == groupB.revision && DecryptedGroupUtil.changeIsEmpty(GroupChangeReconstruct.reconstructGroupChange(groupA, groupB)) ); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java index ebd5253cc1..5cf726bde4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java @@ -18,8 +18,6 @@ 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.DecryptedPendingMember; -import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemoval; -import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; import org.thoughtcrime.securesms.database.GroupTable; import org.thoughtcrime.securesms.database.MessageTable; import org.thoughtcrime.securesms.database.RecipientTable; @@ -101,9 +99,9 @@ public class GroupsV2StateProcessor { public GroupsV2StateProcessor(@NonNull Context context) { this.context = context.getApplicationContext(); this.groupsV2Authorization = ApplicationDependencies.getGroupsV2Authorization(); - this.groupsV2Api = ApplicationDependencies.getSignalServiceAccountManager().getGroupsV2Api(); - this.recipientTable = SignalDatabase.recipients(); - this.groupDatabase = SignalDatabase.groups(); + this.groupsV2Api = ApplicationDependencies.getSignalServiceAccountManager().getGroupsV2Api(); + this.recipientTable = SignalDatabase.recipients(); + this.groupDatabase = SignalDatabase.groups(); } public StateProcessorForGroup forGroup(@NonNull ServiceIds serviceIds, @NonNull GroupMasterKey groupMasterKey) { @@ -150,9 +148,8 @@ public class GroupsV2StateProcessor { public static final class StateProcessorForGroup { private final ServiceIds serviceIds; - private final Context context; - private final GroupTable groupDatabase; - private final GroupsV2Api groupsV2Api; + private final GroupTable groupDatabase; + private final GroupsV2Api groupsV2Api; private final GroupsV2Authorization groupsV2Authorization; private final GroupMasterKey masterKey; private final GroupId.V2 groupId; @@ -160,12 +157,12 @@ public class GroupsV2StateProcessor { private final ProfileAndMessageHelper profileAndMessageHelper; private StateProcessorForGroup(@NonNull ServiceIds serviceIds, - @NonNull Context context, - @NonNull GroupTable groupDatabase, - @NonNull GroupsV2Api groupsV2Api, - @NonNull GroupsV2Authorization groupsV2Authorization, - @NonNull GroupMasterKey groupMasterKey, - @NonNull RecipientTable recipientTable) + @NonNull Context context, + @NonNull GroupTable groupDatabase, + @NonNull GroupsV2Api groupsV2Api, + @NonNull GroupsV2Authorization groupsV2Authorization, + @NonNull GroupMasterKey groupMasterKey, + @NonNull RecipientTable recipientTable) { this(serviceIds, context, groupDatabase, groupsV2Api, groupsV2Authorization, groupMasterKey, GroupSecretParams.deriveFromMasterKey(groupMasterKey), recipientTable); } @@ -180,7 +177,6 @@ public class GroupsV2StateProcessor { @NonNull RecipientTable recipientTable) { this.serviceIds = serviceIds; - this.context = context; this.groupDatabase = groupDatabase; this.groupsV2Api = groupsV2Api; this.groupsV2Authorization = groupsV2Authorization; @@ -191,7 +187,6 @@ public class GroupsV2StateProcessor { } @VisibleForTesting StateProcessorForGroup(@NonNull ServiceIds serviceIds, - @NonNull Context context, @NonNull GroupTable groupDatabase, @NonNull GroupsV2Api groupsV2Api, @NonNull GroupsV2Authorization groupsV2Authorization, @@ -199,7 +194,6 @@ public class GroupsV2StateProcessor { @NonNull ProfileAndMessageHelper profileAndMessageHelper) { this.serviceIds = serviceIds; - this.context = context; this.groupDatabase = groupDatabase; this.groupsV2Api = groupsV2Api; this.groupsV2Authorization = groupsV2Authorization; @@ -232,18 +226,18 @@ public class GroupsV2StateProcessor { DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(localState, serverState); GlobalGroupState inputGroupState = new GlobalGroupState(localState, Collections.singletonList(new ServerGroupLogEntry(serverState, decryptedGroupChange))); - AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(inputGroupState, serverState.getRevision()); + AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(inputGroupState, serverState.revision); DecryptedGroup newLocalState = advanceGroupStateResult.getNewGlobalGroupState().getLocalState(); if (newLocalState == null || newLocalState == inputGroupState.getLocalState()) { info("Local state and server state are equal"); return new GroupUpdateResult(GroupState.GROUP_CONSISTENT_OR_AHEAD, null); } else { - info("Local state (revision: " + localState.getRevision() + ") does not match server state (revision: " + serverState.getRevision() + "), updating"); + info("Local state (revision: " + localState.revision + ") does not match server state (revision: " + serverState.revision + "), updating"); } updateLocalDatabaseGroupState(inputGroupState, newLocalState); - if (localState.getRevision() == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { + if (localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { info("Inserting single update message for restore placeholder"); profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null))); } else { @@ -291,8 +285,8 @@ public class GroupsV2StateProcessor { if (signedGroupChange != null && localState != null && - localState.getRevision() + 1 == signedGroupChange.getRevision() && - revision == signedGroupChange.getRevision()) + localState.revision + 1 == signedGroupChange.revision && + revision == signedGroupChange.revision) { if (notInGroupAndNotBeingAdded(localRecord, signedGroupChange) && notHavingInviteRevoked(signedGroupChange)) { @@ -351,7 +345,7 @@ public class GroupsV2StateProcessor { } updateLocalDatabaseGroupState(inputGroupState, newLocalState); - if (localState != null && localState.getRevision() == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { + if (localState != null && localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { info("Inserting single update message for restore placeholder"); profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null))); } else { @@ -361,7 +355,7 @@ public class GroupsV2StateProcessor { GlobalGroupState remainingWork = advanceGroupStateResult.getNewGlobalGroupState(); if (remainingWork.getServerHistory().size() > 0) { - info(String.format(Locale.US, "There are more revisions on the server for this group, scheduling for later, V[%d..%d]", newLocalState.getRevision() + 1, remainingWork.getLatestRevisionNumber())); + info(String.format(Locale.US, "There are more revisions on the server for this group, scheduling for later, V[%d..%d]", newLocalState.revision + 1, remainingWork.getLatestRevisionNumber())); ApplicationDependencies.getJobManager().add(new RequestGroupV2InfoJob(groupId, remainingWork.getLatestRevisionNumber())); } @@ -371,21 +365,21 @@ public class GroupsV2StateProcessor { private boolean notInGroupAndNotBeingAdded(@NonNull Optional localRecord, @NonNull DecryptedGroupChange signedGroupChange) { boolean currentlyInGroup = localRecord.isPresent() && localRecord.get().isActive(); - boolean addedAsMember = signedGroupChange.getNewMembersList() + boolean addedAsMember = signedGroupChange.newMembers .stream() - .map(DecryptedMember::getAciBytes) + .map(m -> m.aciBytes) .map(ACI::parseOrNull) .filter(Objects::nonNull) .anyMatch(serviceIds::matches); - boolean addedAsPendingMember = signedGroupChange.getNewPendingMembersList() + boolean addedAsPendingMember = signedGroupChange.newPendingMembers .stream() - .map(DecryptedPendingMember::getServiceIdBytes) + .map(m -> m.serviceIdBytes) .anyMatch(serviceIds::matches); - boolean addedAsRequestingMember = signedGroupChange.getNewRequestingMembersList() + boolean addedAsRequestingMember = signedGroupChange.newRequestingMembers .stream() - .map(DecryptedRequestingMember::getAciBytes) + .map(m -> m.aciBytes) .map(ACI::parseOrNull) .filter(Objects::nonNull) .anyMatch(serviceIds::matches); @@ -394,9 +388,9 @@ public class GroupsV2StateProcessor { } private boolean notHavingInviteRevoked(@NonNull DecryptedGroupChange signedGroupChange) { - boolean havingInviteRevoked = signedGroupChange.getDeletePendingMembersList() + boolean havingInviteRevoked = signedGroupChange.deletePendingMembers .stream() - .map(DecryptedPendingMemberRemoval::getServiceIdBytes) + .map(m -> m.serviceIdBytes) .anyMatch(serviceIds::matches); return !havingInviteRevoked; @@ -406,7 +400,7 @@ public class GroupsV2StateProcessor { * Using network, attempt to bring the local copy of the group up to the revision specified via paging. */ private GroupUpdateResult updateLocalGroupFromServerPaged(int revision, DecryptedGroup localState, long timestamp, boolean forceIncludeFirst) throws IOException, GroupNotAMemberException { - boolean latestRevisionOnly = revision == LATEST && (localState == null || localState.getRevision() == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION); + boolean latestRevisionOnly = revision == LATEST && (localState == null || localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION); info("Paging from server revision: " + (revision == LATEST ? "latest" : revision) + ", latestOnly: " + latestRevisionOnly); @@ -421,7 +415,7 @@ public class GroupsV2StateProcessor { throw new IOException(e); } - if (localState != null && localState.getRevision() >= latestServerGroup.getRevision() && GroupProtoUtil.isMember(serviceIds.getAci(), localState.getMembersList())) { + if (localState != null && localState.revision >= latestServerGroup.getRevision() && GroupProtoUtil.isMember(serviceIds.getAci(), localState.members)) { info("Local state is at or later than server"); return new GroupUpdateResult(GroupState.GROUP_CONSISTENT_OR_AHEAD, null); } @@ -431,16 +425,16 @@ public class GroupsV2StateProcessor { inputGroupState = new GlobalGroupState(localState, Collections.singletonList(new ServerGroupLogEntry(latestServerGroup.getFullyDecryptedGroup(), null))); } else { int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, serviceIds.getAci()); - int logsNeededFrom = localState != null ? Math.max(localState.getRevision(), revisionWeWereAdded) : revisionWeWereAdded; + int logsNeededFrom = localState != null ? Math.max(localState.revision, revisionWeWereAdded) : revisionWeWereAdded; boolean includeFirstState = forceIncludeFirst || localState == null || - localState.getRevision() < 0 || - localState.getRevision() == revisionWeWereAdded || - !GroupProtoUtil.isMember(serviceIds.getAci(), localState.getMembersList()) || - (revision == LATEST && localState.getRevision() + 1 < latestServerGroup.getRevision()); + localState.revision < 0 || + localState.revision == revisionWeWereAdded || + !GroupProtoUtil.isMember(serviceIds.getAci(), localState.members) || + (revision == LATEST && localState.revision + 1 < latestServerGroup.getRevision()); - info("Requesting from server currentRevision: " + (localState != null ? localState.getRevision() : "null") + + info("Requesting from server currentRevision: " + (localState != null ? localState.revision : "null") + " logsNeededFrom: " + logsNeededFrom + " includeFirstState: " + includeFirstState + " forceIncludeFirst: " + forceIncludeFirst); @@ -456,10 +450,10 @@ public class GroupsV2StateProcessor { while (hasMore) { AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(inputGroupState, revision); DecryptedGroup newLocalState = advanceGroupStateResult.getNewGlobalGroupState().getLocalState(); - info("Advanced group to revision: " + (newLocalState != null ? newLocalState.getRevision() : "null")); + info("Advanced group to revision: " + (newLocalState != null ? newLocalState.revision : "null")); if (newLocalState != null && !inputGroupState.hasMore() && !forceIncludeFirst) { - int newLocalRevision = newLocalState.getRevision(); + int newLocalRevision = newLocalState.revision; int requestRevision = (revision == LATEST) ? latestServerGroup.getRevision() : revision; if (newLocalRevision < requestRevision) { warn( "Paging again with force first snapshot enabled due to error processing changes. New local revision [" + newLocalRevision + "] hasn't reached our desired level [" + requestRevision + "]"); @@ -473,7 +467,7 @@ public class GroupsV2StateProcessor { updateLocalDatabaseGroupState(inputGroupState, newLocalState); - if (localState == null || localState.getRevision() != GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { + if (localState == null || localState.revision != GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { timestamp = profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries()); } @@ -491,12 +485,12 @@ public class GroupsV2StateProcessor { hasMore = inputGroupState.hasMore(); if (hasMore) { - info("Request next page from server revision: " + finalState.getRevision() + " nextPageRevision: " + inputGroupState.getNextPageRevision()); + info("Request next page from server revision: " + finalState.revision + " nextPageRevision: " + inputGroupState.getNextPageRevision()); inputGroupState = getFullMemberHistoryPage(finalState, inputGroupState.getNextPageRevision(), false); } } - if (localState != null && localState.getRevision() == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { + if (localState != null && localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) { info("Inserting single update message for restore placeholder"); profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(finalState, null))); } @@ -504,7 +498,7 @@ public class GroupsV2StateProcessor { profileAndMessageHelper.persistLearnedProfileKeys(profileKeys); if (finalGlobalGroupState.getServerHistory().size() > 0) { - info(String.format(Locale.US, "There are more revisions on the server for this group, scheduling for later, V[%d..%d]", finalState.getRevision() + 1, finalGlobalGroupState.getLatestRevisionNumber())); + info(String.format(Locale.US, "There are more revisions on the server for this group, scheduling for later, V[%d..%d]", finalState.revision + 1, finalGlobalGroupState.getLatestRevisionNumber())); ApplicationDependencies.getJobManager().add(new RequestGroupV2InfoJob(groupId, finalGlobalGroupState.getLatestRevisionNumber())); } @@ -557,13 +551,13 @@ public class GroupsV2StateProcessor { .requireV2GroupProperties() .getDecryptedGroup(); - DecryptedGroup simulatedGroupState = DecryptedGroupUtil.removeMember(decryptedGroup, serviceIds.getAci(), decryptedGroup.getRevision() + 1); + DecryptedGroup simulatedGroupState = DecryptedGroupUtil.removeMember(decryptedGroup, serviceIds.getAci(), decryptedGroup.revision + 1); - DecryptedGroupChange simulatedGroupChange = DecryptedGroupChange.newBuilder() - .setEditorServiceIdBytes(ACI.UNKNOWN.toByteString()) - .setRevision(simulatedGroupState.getRevision()) - .addDeleteMembers(serviceIds.getAci().toByteString()) - .build(); + DecryptedGroupChange simulatedGroupChange = new DecryptedGroupChange.Builder() + .editorServiceIdBytes(ACI.UNKNOWN.toByteString()) + .revision(simulatedGroupState.revision) + .deleteMembers(Collections.singletonList(serviceIds.getAci().toByteString())) + .build(); DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(decryptedGroup, simulatedGroupChange, simulatedGroupState), null); OutgoingMessage leaveMessage = OutgoingMessage.groupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis()); @@ -605,14 +599,14 @@ public class GroupsV2StateProcessor { Log.w(TAG, "Group create failed, trying to update"); groupDatabase.update(masterKey, newLocalState); } - needsAvatarFetch = !TextUtils.isEmpty(newLocalState.getAvatar()); + needsAvatarFetch = !TextUtils.isEmpty(newLocalState.avatar); } else { groupDatabase.update(masterKey, newLocalState); - needsAvatarFetch = !newLocalState.getAvatar().equals(inputGroupState.getLocalState().getAvatar()); + needsAvatarFetch = !newLocalState.avatar.equals(inputGroupState.getLocalState().avatar); } if (needsAvatarFetch) { - ApplicationDependencies.getJobManager().add(new AvatarGroupsV2DownloadJob(groupId, newLocalState.getAvatar())); + ApplicationDependencies.getJobManager().add(new AvatarGroupsV2DownloadJob(groupId, newLocalState.avatar)); } profileAndMessageHelper.determineProfileSharing(inputGroupState, newLocalState); @@ -681,25 +675,25 @@ public class GroupsV2StateProcessor { void determineProfileSharing(@NonNull GlobalGroupState inputGroupState, @NonNull DecryptedGroup newLocalState) { if (inputGroupState.getLocalState() != null) { - boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByAci(inputGroupState.getLocalState().getMembersList(), aci).isPresent(); + boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByAci(inputGroupState.getLocalState().members, aci).isPresent(); if (wasAMemberAlready) { return; } } - Optional selfAsMemberOptional = DecryptedGroupUtil.findMemberByAci(newLocalState.getMembersList(), aci); - Optional selfAsPendingOptional = DecryptedGroupUtil.findPendingByServiceId(newLocalState.getPendingMembersList(), aci); + Optional selfAsMemberOptional = DecryptedGroupUtil.findMemberByAci(newLocalState.members, aci); + Optional selfAsPendingOptional = DecryptedGroupUtil.findPendingByServiceId(newLocalState.pendingMembers, aci); if (selfAsMemberOptional.isPresent()) { DecryptedMember selfAsMember = selfAsMemberOptional.get(); - int revisionJoinedAt = selfAsMember.getJoinedAtRevision(); + int revisionJoinedAt = selfAsMember.joinedAtRevision; Optional addedByOptional = Stream.of(inputGroupState.getServerHistory()) .map(ServerGroupLogEntry::getChange) - .filter(c -> c != null && c.getRevision() == revisionJoinedAt) + .filter(c -> c != null && c.revision == revisionJoinedAt) .findFirst() - .map(c -> Optional.ofNullable(ServiceId.parseOrNull(c.getEditorServiceIdBytes())) + .map(c -> Optional.ofNullable(ServiceId.parseOrNull(c.editorServiceIdBytes)) .map(Recipient::externalPush)) .orElse(Optional.empty()); @@ -724,7 +718,7 @@ public class GroupsV2StateProcessor { Log.w(TAG, "Could not find founding member during gv2 create. Not enabling profile sharing."); } } else if (selfAsPendingOptional.isPresent()) { - Optional addedBy = selfAsPendingOptional.flatMap(adder -> Optional.ofNullable(UuidUtil.fromByteStringOrNull(adder.getAddedByAci())) + Optional addedBy = selfAsPendingOptional.flatMap(adder -> Optional.ofNullable(UuidUtil.fromByteStringOrNull(adder.addedByAci)) .map(uuid -> Recipient.externalPush(ACI.from(uuid)))); if (addedBy.isPresent() && addedBy.get().isBlocked()) { @@ -825,14 +819,14 @@ public class GroupsV2StateProcessor { } private Optional getEditor(@NonNull DecryptedGroupV2Context decryptedGroupV2Context) { - DecryptedGroupChange change = decryptedGroupV2Context.getChange(); + DecryptedGroupChange change = decryptedGroupV2Context.change; Optional changeEditor = DecryptedGroupUtil.editorServiceId(change); if (changeEditor.isPresent()) { return changeEditor; } else { - Optional pending = DecryptedGroupUtil.findPendingByServiceId(decryptedGroupV2Context.getGroupState().getPendingMembersList(), aci); + Optional pending = DecryptedGroupUtil.findPendingByServiceId(decryptedGroupV2Context.groupState.pendingMembers, aci); if (pending.isPresent()) { - return Optional.ofNullable(ACI.parseOrNull(pending.get().getAddedByAci())); + return Optional.ofNullable(ACI.parseOrNull(pending.get().addedByAci)); } } return Optional.empty(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/LocalGroupLogEntry.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/LocalGroupLogEntry.java index 5692340ec1..3e31884dce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/LocalGroupLogEntry.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/LocalGroupLogEntry.java @@ -21,7 +21,7 @@ final class LocalGroupLogEntry { @Nullable private final DecryptedGroupChange change; LocalGroupLogEntry(@NonNull DecryptedGroup group, @Nullable DecryptedGroupChange change) { - if (change != null && group.getRevision() != change.getRevision()) { + if (change != null && group.revision != change.revision) { throw new AssertionError(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/ServerGroupLogEntry.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/ServerGroupLogEntry.java index 9f68f1e0a4..28479bf1ca 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/ServerGroupLogEntry.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/ServerGroupLogEntry.java @@ -21,7 +21,7 @@ final class ServerGroupLogEntry { @Nullable private final DecryptedGroupChange change; ServerGroupLogEntry(@Nullable DecryptedGroup group, @Nullable DecryptedGroupChange change) { - if (change != null && group != null && group.getRevision() != change.getRevision()) { + if (change != null && group != null && group.revision != change.revision) { Log.w(TAG, "Ignoring change with revision number not matching group"); change = null; } @@ -43,8 +43,8 @@ final class ServerGroupLogEntry { } int getRevision() { - if (group != null) return group.getRevision(); - else if (change != null) return change.getRevision(); + if (group != null) return group.revision; + else if (change != null) return change.revision; else throw new AssertionError(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt index 5b9882fcd2..4818056256 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageJobMigration.kt @@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.util.Base64 import org.whispersystems.signalservice.api.crypto.protos.CompleteMessage import org.whispersystems.signalservice.api.crypto.protos.EnvelopeMetadata import org.whispersystems.signalservice.api.push.ServiceId -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Envelope import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceContentProto /** @@ -60,33 +60,33 @@ class PushProcessMessageJobMigration : JobMigration(10) { Log.i(TAG, "Migrating PushProcessJob to V2") val protoBytes: ByteArray = Base64.decode(inputData.getString("message_content")) - val proto = SignalServiceContentProto.parseFrom(protoBytes) + val proto = SignalServiceContentProto.ADAPTER.decode(protoBytes) - val sourceServiceId = ServiceId.parseOrThrow(proto.metadata.address.uuid) - val destinationServiceId = ServiceId.parseOrThrow(proto.metadata.destinationUuid) + val sourceServiceId = ServiceId.parseOrThrow(proto.metadata!!.address!!.uuid!!) + val destinationServiceId = ServiceId.parseOrThrow(proto.metadata!!.destinationUuid!!) - val envelope = Envelope.newBuilder() - .setSourceServiceId(sourceServiceId.toString()) - .setSourceDevice(proto.metadata.senderDevice) - .setDestinationServiceId(destinationServiceId.toString()) - .setTimestamp(proto.metadata.timestamp) - .setServerGuid(proto.metadata.serverGuid) - .setServerTimestamp(proto.metadata.serverReceivedTimestamp) + val envelope = Envelope.Builder() + .sourceServiceId(sourceServiceId.toString()) + .sourceDevice(proto.metadata!!.senderDevice) + .destinationServiceId(destinationServiceId.toString()) + .timestamp(proto.metadata!!.timestamp) + .serverGuid(proto.metadata!!.serverGuid) + .serverTimestamp(proto.metadata!!.serverReceivedTimestamp) val metadata = EnvelopeMetadata( sourceServiceId = sourceServiceId.toByteArray().toByteString(), - sourceE164 = if (proto.metadata.address.hasE164()) proto.metadata.address.e164 else null, - sourceDeviceId = proto.metadata.senderDevice, - sealedSender = proto.metadata.needsReceipt, - groupId = if (proto.metadata.hasGroupId()) proto.metadata.groupId.toByteArray().toByteString() else null, + sourceE164 = if (proto.metadata?.address?.e164 != null) proto.metadata!!.address!!.e164 else null, + sourceDeviceId = proto.metadata!!.senderDevice!!, + sealedSender = proto.metadata!!.needsReceipt!!, + groupId = if (proto.metadata?.groupId != null) proto.metadata!!.groupId!! else null, destinationServiceId = destinationServiceId.toByteArray().toByteString() ) val completeMessage = CompleteMessage( - envelope = envelope.build().toByteArray().toByteString(), - content = proto.content.toByteArray().toByteString(), + envelope = envelope.build().encodeByteString(), + content = proto.content!!.encodeByteString(), metadata = metadata, - serverDeliveredTimestamp = proto.metadata.serverDeliveredTimestamp + serverDeliveredTimestamp = proto.metadata!!.serverDeliveredTimestamp!! ) return jobData diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageQueueJobMigration.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageQueueJobMigration.java index 1720e64b7c..b5a0b432fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageQueueJobMigration.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migrations/PushProcessMessageQueueJobMigration.java @@ -8,8 +8,8 @@ import org.signal.core.util.logging.Log; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.groups.GroupMasterKey; import org.thoughtcrime.securesms.groups.GroupId; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.JobMigration; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.Base64; @@ -55,19 +55,19 @@ public class PushProcessMessageQueueJobMigration extends JobMigration { String suffix = ""; if (data.getInt("message_state") == 0) { - SignalServiceContentProto proto = SignalServiceContentProto.parseFrom(Base64.decode(data.getString("message_content"))); + SignalServiceContentProto proto = SignalServiceContentProto.ADAPTER.decode(Base64.decode(data.getString("message_content"))); - if (proto != null && proto.hasContent() && proto.getContent().hasDataMessage() && proto.getContent().getDataMessage().hasGroupV2()) { + if (proto != null && proto.content != null && proto.content.dataMessage != null && proto.content.dataMessage.groupV2 != null) { Log.i(TAG, "Migrating a group message."); - GroupId groupId = GroupId.v2(new GroupMasterKey(proto.getContent().getDataMessage().getGroupV2().getMasterKey().toByteArray())); + GroupId groupId = GroupId.v2(new GroupMasterKey(proto.content.dataMessage.groupV2.masterKey.toByteArray())); Recipient recipient = Recipient.externalGroupExact(groupId); suffix = recipient.getId().toQueueKey(); - } else if (proto != null && proto.hasMetadata() && proto.getMetadata().hasAddress()) { + } else if (proto != null && proto.metadata != null && proto.metadata.address != null) { Log.i(TAG, "Migrating an individual message."); - ServiceId senderServiceId = ServiceId.parseOrThrow(proto.getMetadata().getAddress().getUuid()); - String senderE164 = proto.getMetadata().getAddress().getE164(); + ServiceId senderServiceId = ServiceId.parseOrThrow(proto.metadata.address.uuid); + String senderE164 = proto.metadata.address.e164; SignalServiceAddress sender = new SignalServiceAddress(senderServiceId, Optional.ofNullable(senderE164)); suffix = RecipientId.from(sender).toQueueKey(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java index 84b8ac0721..6f6934d5a2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java @@ -9,8 +9,8 @@ import org.thoughtcrime.securesms.database.MessageTable; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.databaseprotos.DeviceLastResetTime; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.DecryptionsDrainedConstraint; import org.thoughtcrime.securesms.notifications.v2.ConversationId; import org.thoughtcrime.securesms.recipients.Recipient; @@ -23,6 +23,8 @@ import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -146,26 +148,28 @@ public class AutomaticSessionResetJob extends BaseJob { } private long getLastResetTime(@NonNull DeviceLastResetTime resetTimes, int deviceId) { - for (DeviceLastResetTime.Pair pair : resetTimes.getResetTimeList()) { - if (pair.getDeviceId() == deviceId) { - return pair.getLastResetTime(); + for (DeviceLastResetTime.Pair pair : resetTimes.resetTime) { + if (pair.deviceId == deviceId) { + return pair.lastResetTime; } } return 0; } private @NonNull DeviceLastResetTime setLastResetTime(@NonNull DeviceLastResetTime resetTimes, int deviceId, long time) { - DeviceLastResetTime.Builder builder = DeviceLastResetTime.newBuilder(); + DeviceLastResetTime.Builder builder = new DeviceLastResetTime.Builder(); - for (DeviceLastResetTime.Pair pair : resetTimes.getResetTimeList()) { - if (pair.getDeviceId() != deviceId) { - builder.addResetTime(pair); + List newResetTimes = new ArrayList<>(resetTimes.resetTime.size()); + for (DeviceLastResetTime.Pair pair : resetTimes.resetTime) { + if (pair.deviceId != deviceId) { + newResetTimes.add(pair); } } - builder.addResetTime(DeviceLastResetTime.Pair.newBuilder().setDeviceId(deviceId).setLastResetTime(time)); - return builder.build(); + newResetTimes.add(new DeviceLastResetTime.Pair.Builder().deviceId(deviceId).lastResetTime(time).build()); + + return builder.resetTime(newResetTimes).build(); } public static final class Factory implements Job.Factory { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLinkUpdateSendJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLinkUpdateSendJob.kt index f2b8941753..6abe96571f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLinkUpdateSendJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLinkUpdateSendJob.kt @@ -5,7 +5,7 @@ package org.thoughtcrime.securesms.jobs -import com.google.protobuf.ByteString +import okio.ByteString.Companion.toByteString import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.dependencies.ApplicationDependencies @@ -17,8 +17,7 @@ import org.thoughtcrime.securesms.util.FeatureFlags import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallLinkUpdate -import java.lang.Exception +import org.whispersystems.signalservice.internal.push.SyncMessage.CallLinkUpdate import java.util.Optional import java.util.concurrent.TimeUnit @@ -68,9 +67,7 @@ class CallLinkUpdateSendJob private constructor( return } - val callLinkUpdate = CallLinkUpdate.newBuilder() - .setRootKey(ByteString.copyFrom(callLink.credentials.linkKeyBytes)) - .build() + val callLinkUpdate = CallLinkUpdate(rootKey = callLink.credentials.linkKeyBytes.toByteString()) ApplicationDependencies.getSignalServiceMessageSender() .sendSyncMessage(SignalServiceSyncMessage.forCallLinkUpdate(callLinkUpdate), Optional.empty()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLogEventSendJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLogEventSendJob.kt index 70d1100529..78412cb8b1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLogEventSendJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/CallLogEventSendJob.kt @@ -5,7 +5,6 @@ package org.thoughtcrime.securesms.jobs -import okio.ByteString import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobmanager.Job import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint @@ -13,7 +12,7 @@ import org.thoughtcrime.securesms.jobs.protos.CallLogEventSendJobData import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.SyncMessage import java.util.Optional import java.util.concurrent.TimeUnit @@ -22,7 +21,7 @@ import java.util.concurrent.TimeUnit */ class CallLogEventSendJob private constructor( parameters: Parameters, - private val callLogEvent: SignalServiceProtos.SyncMessage.CallLogEvent + private val callLogEvent: SyncMessage.CallLogEvent ) : BaseJob(parameters) { companion object { @@ -37,16 +36,15 @@ class CallLogEventSendJob private constructor( .setMaxAttempts(Parameters.UNLIMITED) .addConstraint(NetworkConstraint.KEY) .build(), - SignalServiceProtos.SyncMessage.CallLogEvent - .newBuilder() - .setTimestamp(timestamp) - .setType(SignalServiceProtos.SyncMessage.CallLogEvent.Type.CLEAR) - .build() + SyncMessage.CallLogEvent( + timestamp = timestamp, + type = SyncMessage.CallLogEvent.Type.CLEAR + ) ) } override fun serialize(): ByteArray = CallLogEventSendJobData.Builder() - .callLogEvent(ByteString.of(*callLogEvent.toByteArray())) + .callLogEvent(callLogEvent.encodeByteString()) .build() .encode() @@ -74,7 +72,7 @@ class CallLogEventSendJob private constructor( override fun create(parameters: Parameters, serializedData: ByteArray?): CallLogEventSendJob { return CallLogEventSendJob( parameters, - SignalServiceProtos.SyncMessage.CallLogEvent.parseFrom( + SyncMessage.CallLogEvent.ADAPTER.decode( CallLogEventSendJobData.ADAPTER.decode(serializedData!!).callLogEvent.toByteArray() ) ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/CallSyncEventJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/CallSyncEventJob.kt index f467989088..5df5f5c27e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/CallSyncEventJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/CallSyncEventJob.kt @@ -14,7 +14,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.ringrtc.RemotePeer import org.thoughtcrime.securesms.service.webrtc.CallEventSyncMessageUtil import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.SyncMessage import java.util.Optional import java.util.concurrent.TimeUnit @@ -120,7 +120,7 @@ class CallSyncEventJob private constructor( } } - private fun createSyncMessage(syncTimestamp: Long, callSyncEvent: CallSyncEventJobRecord, callType: CallTable.Type): SignalServiceProtos.SyncMessage.CallEvent { + private fun createSyncMessage(syncTimestamp: Long, callSyncEvent: CallSyncEventJobRecord, callType: CallTable.Type): SyncMessage.CallEvent { return when (callSyncEvent.deserializeEvent()) { CallTable.Event.ACCEPTED -> CallEventSyncMessageUtil.createAcceptedSyncMessage( remotePeer = RemotePeer(callSyncEvent.deserializeRecipientId(), CallId(callSyncEvent.callId)), diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java index 29f47fd092..d8295a271c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/DonationReceiptRedemptionJob.java @@ -14,9 +14,9 @@ import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JobManager; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.util.MessageRecordUtil; @@ -254,12 +254,12 @@ public class DonationReceiptRedemptionJob extends BaseJob { if (MessageRecordUtil.hasGiftBadge(messageRecord)) { GiftBadge giftBadge = MessageRecordUtil.requireGiftBadge(messageRecord); - if (giftBadge.getRedemptionState() == GiftBadge.RedemptionState.REDEEMED) { + if (giftBadge.redemptionState == GiftBadge.RedemptionState.REDEEMED) { Log.d(TAG, "Already redeemed this gift badge. Exiting.", true); return null; } else { - Log.d(TAG, "Attempting redemption of badge in state " + giftBadge.getRedemptionState().name()); - return new ReceiptCredentialPresentation(giftBadge.getRedemptionToken().toByteArray()); + Log.d(TAG, "Attempting redemption of badge in state " + giftBadge.redemptionState.name()); + return new ReceiptCredentialPresentation(giftBadge.redemptionToken.toByteArray()); } } else { Log.d(TAG, "No gift badge on message record. Exiting.", true); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt index 42a9a2e5a6..7a7e4801e7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt @@ -1,6 +1,6 @@ package org.thoughtcrime.securesms.jobs -import com.google.protobuf.ByteString +import okio.ByteString.Companion.toByteString import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.badges.gifts.Gifts import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey @@ -63,7 +63,7 @@ class GiftSendJob private constructor(parameters: Parameters, private val recipi recipient = recipient, expiresIn = TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong()), sentTimestamp = System.currentTimeMillis(), - giftBadge = GiftBadge.newBuilder().setRedemptionToken(ByteString.copyFrom(token)).build() + giftBadge = GiftBadge(redemptionToken = token.toByteString()) ) Log.i(TAG, "Sending gift badge to $recipientId...") diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java index a9ea0650ef..a9d8fa1194 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java @@ -4,8 +4,6 @@ import androidx.annotation.AnyThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.ByteString; - import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; import org.signal.storageservice.protos.groups.local.DecryptedMember; @@ -18,20 +16,21 @@ import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.groups.GroupInsufficientRightsException; import org.thoughtcrime.securesms.groups.GroupManager; import org.thoughtcrime.securesms.groups.GroupNotAMemberException; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.DecryptionsDrainedConstraint; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.whispersystems.signalservice.api.groupsv2.NoCredentialForRedemptionTimeException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; -import org.whispersystems.signalservice.api.util.UuidUtil; import java.io.IOException; import java.util.Optional; import java.util.concurrent.TimeUnit; +import okio.ByteString; + /** * When your profile key changes, this job can be used to update it on a single given group. *

@@ -96,7 +95,7 @@ public final class GroupV2UpdateSelfProfileKeyJob extends BaseJob { return; } - ByteString selfProfileKey = ByteString.copyFrom(rawProfileKey); + ByteString selfProfileKey = ByteString.of(rawProfileKey); long timeSinceLastCheck = System.currentTimeMillis() - SignalStore.misc().getLastGv2ProfileCheckTime(); @@ -120,13 +119,13 @@ public final class GroupV2UpdateSelfProfileKeyJob extends BaseJob { } ByteString selfUuidBytes = Recipient.self().requireAci().toByteString(); - DecryptedMember selfMember = group.get().requireV2GroupProperties().getDecryptedGroup().getMembersList() + DecryptedMember selfMember = group.get().requireV2GroupProperties().getDecryptedGroup().members .stream() - .filter(m -> m.getAciBytes().equals(selfUuidBytes)) + .filter(m -> m.aciBytes.equals(selfUuidBytes)) .findFirst() .orElse(null); - if (selfMember != null && !selfMember.getProfileKey().equals(selfProfileKey)) { + if (selfMember != null && !selfMember.profileKey.equals(selfProfileKey)) { Log.w(TAG, "Profile key mismatch for group " + id + " -- enqueueing job"); foundMismatch = true; ApplicationDependencies.getJobManager().add(GroupV2UpdateSelfProfileKeyJob.withQueueLimits(id)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java index 4a28df02be..1e5d7020b0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java @@ -19,9 +19,9 @@ import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JobManager; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.mms.MmsException; @@ -33,7 +33,6 @@ import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException; -import org.thoughtcrime.securesms.util.ConversationUtil; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents; @@ -51,8 +50,8 @@ import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredExcepti import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; import org.whispersystems.signalservice.api.util.UuidUtil; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage; +import org.whispersystems.signalservice.internal.push.BodyRange; +import org.whispersystems.signalservice.internal.push.DataMessage; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceCallLinkSyncJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceCallLinkSyncJob.kt index 488907700c..7add42ad57 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceCallLinkSyncJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceCallLinkSyncJob.kt @@ -5,7 +5,7 @@ package org.thoughtcrime.securesms.jobs -import com.google.protobuf.ByteString +import okio.ByteString.Companion.toByteString import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobmanager.Job @@ -13,13 +13,14 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.service.webrtc.links.CallLinkCredentials import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallLinkUpdate +import org.whispersystems.signalservice.internal.push.SyncMessage.CallLinkUpdate import java.util.Optional import kotlin.time.Duration.Companion.days /** * Sends a sync message to linked devices when a new call link is created locally. */ +// TODO [cody] not being created? class MultiDeviceCallLinkSyncJob private constructor( parameters: Parameters, private val callLinkUpdate: CallLinkUpdate @@ -32,10 +33,10 @@ class MultiDeviceCallLinkSyncJob private constructor( .setLifespan(1.days.inWholeMilliseconds) .setMaxAttempts(Parameters.UNLIMITED) .build(), - CallLinkUpdate.newBuilder() - .setRootKey(ByteString.copyFrom(credentials.linkKeyBytes)) - .setAdminPassKey(ByteString.copyFrom(credentials.adminPassBytes!!)) - .build() + CallLinkUpdate( + rootKey = credentials.linkKeyBytes.toByteString(), + adminPassKey = credentials.adminPassBytes!!.toByteString() + ) ) companion object { @@ -45,7 +46,7 @@ class MultiDeviceCallLinkSyncJob private constructor( } override fun serialize(): ByteArray { - return callLinkUpdate.toByteArray() + return callLinkUpdate.encode() } override fun getFactoryKey(): String = KEY @@ -72,7 +73,7 @@ class MultiDeviceCallLinkSyncJob private constructor( class Factory : Job.Factory { override fun create(parameters: Parameters, serializedData: ByteArray?): MultiDeviceCallLinkSyncJob { - val data = CallLinkUpdate.parseFrom(serializedData) + val data = CallLinkUpdate.ADAPTER.decode(serializedData!!) return MultiDeviceCallLinkSyncJob(parameters, data) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt index 279f948da2..eae7ff23bd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt @@ -32,7 +32,7 @@ class MultiDeviceContactSyncJob(parameters: Parameters, private val attachmentPo Parameters.Builder() .setQueue("MultiDeviceContactSyncJob") .build(), - AttachmentPointerUtil.createAttachmentPointer(contactsAttachment).toByteArray() + AttachmentPointerUtil.createAttachmentPointer(contactsAttachment).encode() ) override fun serialize(): ByteArray? { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceOutgoingPaymentSyncJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceOutgoingPaymentSyncJob.java index d19be0fd2d..c17eac8cc5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceOutgoingPaymentSyncJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceOutgoingPaymentSyncJob.java @@ -3,15 +3,13 @@ package org.thoughtcrime.securesms.jobs; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.ByteString; - import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; import org.thoughtcrime.securesms.database.PaymentTable; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.net.NotPushRegisteredException; import org.thoughtcrime.securesms.payments.proto.PaymentMetaData; @@ -28,6 +26,8 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; +import okio.ByteString; + /** * Tells a linked device about sent payments. */ @@ -87,7 +87,7 @@ public final class MultiDeviceOutgoingPaymentSyncJob extends BaseJob { return; } - PaymentMetaData.MobileCoinTxoIdentification txoIdentification = payment.getPaymentMetaData().getMobileCoinTxoIdentification(); + PaymentMetaData.MobileCoinTxoIdentification txoIdentification = payment.getPaymentMetaData().mobileCoinTxoIdentification; boolean defrag = payment.isDefrag(); @@ -107,13 +107,13 @@ public final class MultiDeviceOutgoingPaymentSyncJob extends BaseJob { OutgoingPaymentMessage outgoingPaymentMessage = new OutgoingPaymentMessage(uuid, payment.getAmount().requireMobileCoin(), payment.getFee().requireMobileCoin(), - ByteString.copyFrom(receipt), + ByteString.of(receipt), payment.getBlockIndex(), payment.getTimestamp(), defrag ? Optional.empty() : Optional.of(payment.getPayee().requirePublicAddress().serialize()), defrag ? Optional.empty() : Optional.of(payment.getNote()), - txoIdentification.getPublicKeyList(), - txoIdentification.getKeyImagesList()); + txoIdentification.publicKey, + txoIdentification.keyImages); ApplicationDependencies.getSignalServiceMessageSender() diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PnpInitializeDevicesJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/PnpInitializeDevicesJob.kt index 6665d50e9a..b2e9a7302c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PnpInitializeDevicesJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PnpInitializeDevicesJob.kt @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs import androidx.annotation.WorkerThread import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers +import okio.ByteString.Companion.toByteString import org.signal.core.util.concurrent.safeBlockingGet import org.signal.core.util.logging.Log import org.signal.core.util.orNull @@ -15,7 +16,6 @@ import org.signal.libsignal.protocol.util.KeyHelper import org.signal.libsignal.protocol.util.Medium import org.thoughtcrime.securesms.components.settings.app.changenumber.ChangeNumberRepository import org.thoughtcrime.securesms.crypto.PreKeyUtil -import org.thoughtcrime.securesms.database.model.toProtoByteString import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobmanager.Job import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint @@ -31,7 +31,7 @@ import org.whispersystems.signalservice.api.push.SignedPreKeyEntity import org.whispersystems.signalservice.internal.ServiceResponse import org.whispersystems.signalservice.internal.push.KyberPreKeyEntity import org.whispersystems.signalservice.internal.push.OutgoingPushMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.SyncMessage import org.whispersystems.signalservice.internal.push.VerifyAccountResponse import org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException import java.io.IOException @@ -212,13 +212,13 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base // Device Messages if (deviceId != primaryDeviceId) { - val pniChangeNumber = SignalServiceProtos.SyncMessage.PniChangeNumber.newBuilder() - .setIdentityKeyPair(pniIdentity.serialize().toProtoByteString()) - .setSignedPreKey(signedPreKeyRecord.serialize().toProtoByteString()) - .setLastResortKyberPreKey(lastResortKyberPreKeyRecord.serialize().toProtoByteString()) - .setRegistrationId(pniRegistrationId) - .setNewE164(newE164) - .build() + val pniChangeNumber = SyncMessage.PniChangeNumber( + identityKeyPair = pniIdentity.serialize().toByteString(), + signedPreKey = signedPreKeyRecord.serialize().toByteString(), + lastResortKyberPreKey = lastResortKyberPreKeyRecord.serialize().toByteString(), + registrationId = pniRegistrationId, + newE164 = newE164 + ) deviceMessages += messageSender.getEncryptedSyncPniInitializeDeviceMessage(deviceId, pniChangeNumber) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java index 6bbcf29006..b698aef5aa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java @@ -19,10 +19,10 @@ import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.NetworkFailure; import org.thoughtcrime.securesms.database.model.MessageId; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JobLogger; import org.thoughtcrime.securesms.jobmanager.JobManager; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.messages.GroupSendUtil; import org.thoughtcrime.securesms.messages.StorySendUtil; @@ -40,7 +40,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage; import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessageRecipient; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.BodyRange; import java.io.IOException; import java.util.ArrayList; @@ -202,8 +202,8 @@ public final class PushDistributionListSendJob extends PushSendJob { rotateSenderCertificateIfNecessary(); List attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList(); - List attachmentPointers = getAttachmentPointersFor(attachments); - List bodyRanges = getBodyRanges(message); + List attachmentPointers = getAttachmentPointersFor(attachments); + List bodyRanges = getBodyRanges(message); boolean isRecipientUpdate = Stream.of(SignalDatabase.groupReceipts().getGroupReceiptInfo(messageId)) .anyMatch(info -> info.getStatus() > GroupReceiptTable.STATUS_UNDELIVERED); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index d86ca7a3d5..688920f09f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -8,7 +8,6 @@ import androidx.annotation.WorkerThread; import com.annimon.stream.Collectors; import com.annimon.stream.Stream; -import com.google.protobuf.ByteString; import org.signal.core.util.SetUtil; import org.signal.core.util.logging.Log; @@ -28,10 +27,10 @@ import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.groups.GroupId; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JobLogger; import org.thoughtcrime.securesms.jobmanager.JobManager; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.messages.GroupSendUtil; import org.thoughtcrime.securesms.messages.StorySendUtil; @@ -59,8 +58,8 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2; +import org.whispersystems.signalservice.internal.push.BodyRange; +import org.whispersystems.signalservice.internal.push.GroupContextV2; import java.io.IOException; import java.util.ArrayList; @@ -72,6 +71,8 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import okio.ByteString; + public final class PushGroupSendJob extends PushSendJob { public static final String KEY = "PushGroupSendJob"; @@ -116,8 +117,8 @@ public final class PushGroupSendJob extends PushSendJob { throw new AssertionError("Not a group!"); } - MessageTable database = SignalDatabase.messages(); - OutgoingMessage message = database.getOutgoingMessage(messageId); + MessageTable database = SignalDatabase.messages(); + OutgoingMessage message = database.getOutgoingMessage(messageId); if (message.getScheduledDate() != -1) { if (!filterAddresses.isEmpty()) { @@ -207,7 +208,8 @@ public final class PushGroupSendJob extends PushSendJob { } try { - log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getThreadRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments())); + log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getThreadRecipient() + .getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments())); if (!groupRecipient.resolve().isProfileSharing() && !database.isGroupQuitMessage(messageId)) { RecipientUtil.shareProfileIfFirstSecureMessage(groupRecipient); @@ -269,8 +271,8 @@ public final class PushGroupSendJob extends PushSendJob { List bodyRanges = getBodyRanges(message); List attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList(); List attachmentPointers = getAttachmentPointersFor(attachments); - boolean isRecipientUpdate = Stream.of(SignalDatabase.groupReceipts().getGroupReceiptInfo(messageId)) - .anyMatch(info -> info.getStatus() > GroupReceiptTable.STATUS_UNDELIVERED); + boolean isRecipientUpdate = Stream.of(SignalDatabase.groupReceipts().getGroupReceiptInfo(messageId)) + .anyMatch(info -> info.getStatus() > GroupReceiptTable.STATUS_UNDELIVERED); if (message.getStoryType().isStory()) { Optional groupRecord = SignalDatabase.groups().getGroup(groupId); @@ -306,10 +308,10 @@ public final class PushGroupSendJob extends PushSendJob { if (message.isV2Group()) { MessageGroupContext.GroupV2Properties properties = message.requireGroupV2Properties(); GroupContextV2 groupContext = properties.getGroupContext(); - SignalServiceGroupV2.Builder builder = SignalServiceGroupV2.newBuilder(properties.getGroupMasterKey()) - .withRevision(groupContext.getRevision()); + SignalServiceGroupV2.Builder builder = SignalServiceGroupV2.newBuilder(properties.getGroupMasterKey()) + .withRevision(groupContext.revision); - ByteString groupChange = groupContext.getGroupChange(); + ByteString groupChange = groupContext.groupChange; if (groupChange != null) { builder.withSignedGroupChange(groupChange.toByteArray()); } @@ -320,7 +322,8 @@ public final class PushGroupSendJob extends PushSendJob { .withExpiration(groupRecipient.getExpiresInSeconds()) .asGroupMessage(group) .build(); - return GroupSendUtil.sendResendableDataMessage(context, groupRecipient.requireGroupId().requireV2(), null, destinations, isRecipientUpdate, ContentHint.IMPLICIT, new MessageId(messageId), groupDataMessage, message.isUrgent(), false, null); + return GroupSendUtil.sendResendableDataMessage(context, groupRecipient.requireGroupId() + .requireV2(), null, destinations, isRecipientUpdate, ContentHint.IMPLICIT, new MessageId(messageId), groupDataMessage, message.isUrgent(), false, null); } else { throw new UndeliverableMessageException("Messages can no longer be sent to V1 groups!"); } @@ -369,8 +372,8 @@ public final class PushGroupSendJob extends PushSendJob { } SignalServiceDataMessage groupMessage = groupMessageBuilder.build(); - SignalServiceEditMessage editMessage = originalEditedMessage != null ? new SignalServiceEditMessage(originalEditedMessage.getDateSent(), groupMessage) - : null; + SignalServiceEditMessage editMessage = originalEditedMessage != null ? new SignalServiceEditMessage(originalEditedMessage.getDateSent(), groupMessage) + : null; Log.i(TAG, JobLogger.format(this, "Beginning message send.")); @@ -411,9 +414,9 @@ public final class PushGroupSendJob extends PushSendJob { MessageTable database = SignalDatabase.messages(); RecipientAccessList accessList = new RecipientAccessList(target); - List networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(accessList.requireIdByAddress(result.getAddress()))).toList(); - List identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null) - .map(result -> new IdentityKeyMismatch(accessList.requireIdByAddress(result.getAddress()), result.getIdentityFailure().getIdentityKey())).toList(); + List networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(accessList.requireIdByAddress(result.getAddress()))).toList(); + List identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null) + .map(result -> new IdentityKeyMismatch(accessList.requireIdByAddress(result.getAddress()), result.getIdentityFailure().getIdentityKey())).toList(); ProofRequiredException proofRequired = Stream.of(results).filter(r -> r.getProofRequiredFailure() != null).findLast().map(SendMessageResult::getProofRequiredFailure).orElse(null); List successes = Stream.of(results).filter(result -> result.getSuccess() != null).toList(); List> successUnidentifiedStatus = Stream.of(successes).map(result -> new Pair<>(accessList.requireIdByAddress(result.getAddress()), result.getSuccess().isUnidentified())).toList(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java index fead90c4a1..7b52271188 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java @@ -8,15 +8,14 @@ import androidx.annotation.WorkerThread; import com.annimon.stream.Collectors; import com.annimon.stream.Stream; -import com.google.protobuf.InvalidProtocolBufferException; import org.signal.core.util.logging.Log; import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.thoughtcrime.securesms.database.RecipientTable; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.groups.GroupId; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.messages.GroupSendUtil; import org.thoughtcrime.securesms.mms.MessageGroupContext; @@ -36,7 +35,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.GroupContextV2; import java.io.IOException; import java.util.ArrayList; @@ -60,10 +59,10 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { private static final String KEY_TIMESTAMP = "timestamp"; private static final String KEY_GROUP_CONTEXT_V2 = "group_context_v2"; - private final List recipients; - private final int initialRecipientCount; - private final SignalServiceProtos.GroupContextV2 groupContextV2; - private final long timestamp; + private final List recipients; + private final int initialRecipientCount; + private final GroupContextV2 groupContextV2; + private final long timestamp; @WorkerThread public static @NonNull Job create(@NonNull Context context, @@ -71,8 +70,8 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { @NonNull DecryptedGroup decryptedGroup, @NonNull OutgoingMessage groupMessage) { - List memberAcis = DecryptedGroupUtil.toAciList(decryptedGroup.getMembersList()); - List pendingServiceIds = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.getPendingMembersList()); + List memberAcis = DecryptedGroupUtil.toAciList(decryptedGroup.members); + List pendingServiceIds = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembers); Stream memberServiceIds = Stream.of(memberAcis) .filter(ACI::isValid) @@ -87,7 +86,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { .collect(Collectors.toSet()); MessageGroupContext.GroupV2Properties properties = groupMessage.requireGroupV2Properties(); - SignalServiceProtos.GroupContextV2 groupContext = properties.getGroupContext(); + GroupContextV2 groupContext = properties.getGroupContext(); String queue = Recipient.externalGroupExact(groupId).getId().toQueueKey(); @@ -105,7 +104,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { private PushGroupSilentUpdateSendJob(@NonNull List recipients, int initialRecipientCount, long timestamp, - @NonNull SignalServiceProtos.GroupContextV2 groupContextV2, + @NonNull GroupContextV2 groupContextV2, @NonNull Parameters parameters) { super(parameters); @@ -121,7 +120,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { return new JsonJobData.Builder().putString(KEY_RECIPIENTS, RecipientId.toSerializedList(recipients)) .putInt(KEY_INITIAL_RECIPIENT_COUNT, initialRecipientCount) .putLong(KEY_TIMESTAMP, timestamp) - .putString(KEY_GROUP_CONTEXT_V2, Base64.encodeBytes(groupContextV2.toByteArray())) + .putString(KEY_GROUP_CONTEXT_V2, Base64.encodeBytes(groupContextV2.encode())) .serialize(); } @@ -136,7 +135,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { throw new NotPushRegisteredException(); } - GroupId.V2 groupId = GroupId.v2(GroupUtil.requireMasterKey(groupContextV2.getMasterKey().toByteArray())); + GroupId.V2 groupId = GroupId.v2(GroupUtil.requireMasterKey(groupContextV2.masterKey.toByteArray())); if (Recipient.externalGroupExact(groupId).isBlocked()) { Log.i(TAG, "Not updating group state for blocked group " + groupId); @@ -201,10 +200,10 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { long timestamp = data.getLong(KEY_TIMESTAMP); byte[] contextBytes = Base64.decodeOrThrow(data.getString(KEY_GROUP_CONTEXT_V2)); - SignalServiceProtos.GroupContextV2 groupContextV2; + GroupContextV2 groupContextV2; try { - groupContextV2 = SignalServiceProtos.GroupContextV2.parseFrom(contextBytes); - } catch (InvalidProtocolBufferException e) { + groupContextV2 = GroupContextV2.ADAPTER.decode(contextBytes); + } catch (IOException e) { throw new AssertionError(e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt index 74b8780108..2a8ab2fd2f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.kt @@ -21,8 +21,8 @@ import org.whispersystems.signalservice.api.crypto.protos.CompleteMessage import org.whispersystems.signalservice.api.groupsv2.NoCredentialForRedemptionTimeException import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope import java.io.IOException import java.util.concurrent.TimeUnit import org.whispersystems.signalservice.api.crypto.protos.EnvelopeMetadata as EnvelopeMetadataProto @@ -39,8 +39,8 @@ class PushProcessMessageJob private constructor( override fun serialize(): ByteArray { return CompleteMessage( - envelope = envelope.toByteArray().toByteString(), - content = content.toByteArray().toByteString(), + envelope = envelope.encodeByteString(), + content = content.encodeByteString(), metadata = EnvelopeMetadataProto( sourceServiceId = ByteString.of(*metadata.sourceServiceId.toByteArray()), sourceE164 = metadata.sourceE164, @@ -76,8 +76,8 @@ class PushProcessMessageJob private constructor( val completeMessage = CompleteMessage.ADAPTER.decode(data!!) PushProcessMessageJob( parameters = parameters, - envelope = Envelope.parseFrom(completeMessage.envelope.toByteArray()), - content = Content.parseFrom(completeMessage.content.toByteArray()), + envelope = Envelope.ADAPTER.decode(completeMessage.envelope.toByteArray()), + content = Content.ADAPTER.decode(completeMessage.content.toByteArray()), metadata = EnvelopeMetadata( sourceServiceId = ServiceId.parseOrThrow(completeMessage.metadata.sourceServiceId.toByteArray()), sourceE164 = completeMessage.metadata.sourceE164, @@ -126,13 +126,13 @@ class PushProcessMessageJob private constructor( if (groupId.isV2) { val localRevision = groups.getGroupV2Revision(groupId.requireV2()) - if (groupContext.revision > localRevision || GroupsV1MigratedCache.hasV1Group(groupId)) { + if (groupContext.revision!! > localRevision || GroupsV1MigratedCache.hasV1Group(groupId)) { Log.i(TAG, "Adding network constraint to group-related job.") requireNetwork = true } } - } else if (result.content.hasSyncMessage() && result.content.syncMessage.hasSent() && result.content.syncMessage.sent.hasDestinationServiceId()) { - queueName = getQueueName(RecipientId.from(ServiceId.parseOrThrow(result.content.syncMessage.sent.destinationServiceId))) + } else if (result.content.syncMessage != null && result.content.syncMessage!!.sent != null && result.content.syncMessage!!.sent!!.destinationServiceId != null) { + queueName = getQueueName(RecipientId.from(ServiceId.parseOrThrow(result.content.syncMessage!!.sent!!.destinationServiceId!!))) } else { queueName = getQueueName(RecipientId.from(result.metadata.sourceServiceId)) } @@ -145,12 +145,12 @@ class PushProcessMessageJob private constructor( if (requireNetwork) { builder.addConstraint(NetworkConstraint.KEY).setLifespan(TimeUnit.DAYS.toMillis(30)) } - PushProcessMessageJob(builder.build(), result.envelope.toBuilder().clearContent().build(), result.content, result.metadata, result.serverDeliveredTimestamp) + PushProcessMessageJob(builder.build(), result.envelope.newBuilder().content(null).build(), result.content, result.metadata, result.serverDeliveredTimestamp) } else { try { messageProcessor.process(result.envelope, result.content, result.metadata, result.serverDeliveredTimestamp, localMetric = localReceiveMetric) } catch (e: Exception) { - Log.e(TAG, "Failed to process message with timestamp ${result.envelope.timestamp}. Dropping.") + Log.e(TAG, "Failed to process message with timestamp ${result.envelope.timestamp}. Dropping.", e) } null } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java index b1643eecbd..80b1992637 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -68,11 +68,10 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServicePreview; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.ServiceId.ACI; -import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.BodyRange; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -333,7 +332,7 @@ public abstract class PushSendJob extends SendJob { String quoteBody = message.getOutgoingQuote().getText(); RecipientId quoteAuthor = message.getOutgoingQuote().getAuthor(); List quoteMentions = getMentionsFor(message.getOutgoingQuote().getMentions()); - List bodyRanges = getBodyRanges(message.getOutgoingQuote().getBodyRanges()); + List bodyRanges = getBodyRanges(message.getOutgoingQuote().getBodyRanges()); QuoteModel.Type quoteType = message.getOutgoingQuote().getType(); List quoteAttachments = new LinkedList<>(); Optional localQuoteAttachment = message.getOutgoingQuote() @@ -463,7 +462,7 @@ public abstract class PushSendJob extends SendJob { } try { - ReceiptCredentialPresentation presentation = new ReceiptCredentialPresentation(giftBadge.getRedemptionToken().toByteArray()); + ReceiptCredentialPresentation presentation = new ReceiptCredentialPresentation(giftBadge.redemptionToken.toByteArray()); return new SignalServiceDataMessage.GiftBadge(presentation); } catch (InvalidInputException invalidInputException) { @@ -471,39 +470,37 @@ public abstract class PushSendJob extends SendJob { } } - protected @Nullable List getBodyRanges(@NonNull OutgoingMessage message) { + protected @Nullable List getBodyRanges(@NonNull OutgoingMessage message) { return getBodyRanges(message.getBodyRanges()); } - protected @Nullable List getBodyRanges(@Nullable BodyRangeList bodyRanges) { - if (bodyRanges == null || bodyRanges.getRangesCount() == 0) { + protected @Nullable List getBodyRanges(@Nullable BodyRangeList bodyRanges) { + if (bodyRanges == null || bodyRanges.ranges.size() == 0) { return null; } return bodyRanges - .getRangesList() + .ranges .stream() .map(range -> { - SignalServiceProtos.BodyRange.Builder builder = SignalServiceProtos.BodyRange.newBuilder() - .setStart(range.getStart()) - .setLength(range.getLength()); + BodyRange.Builder builder = new BodyRange.Builder().start(range.start).length(range.length); - if (range.hasStyle()) { - switch (range.getStyle()) { + if (range.style != null) { + switch (range.style) { case BOLD: - builder.setStyle(SignalServiceProtos.BodyRange.Style.BOLD); + builder.style(BodyRange.Style.BOLD); break; case ITALIC: - builder.setStyle(SignalServiceProtos.BodyRange.Style.ITALIC); + builder.style(BodyRange.Style.ITALIC); break; case SPOILER: - builder.setStyle(SignalServiceProtos.BodyRange.Style.SPOILER); + builder.style(BodyRange.Style.SPOILER); break; case STRIKETHROUGH: - builder.setStyle(SignalServiceProtos.BodyRange.Style.STRIKETHROUGH); + builder.style(BodyRange.Style.STRIKETHROUGH); break; case MONOSPACE: - builder.setStyle(SignalServiceProtos.BodyRange.Style.MONOSPACE); + builder.style(BodyRange.Style.MONOSPACE); break; default: throw new IllegalArgumentException("Unrecognized style"); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshCallLinkDetailsJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshCallLinkDetailsJob.kt index cc42d8fbed..49589ef120 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshCallLinkDetailsJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshCallLinkDetailsJob.kt @@ -13,7 +13,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.service.webrtc.links.CallLinkCredentials import org.thoughtcrime.securesms.service.webrtc.links.ReadCallLinkResult import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkManager -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallLinkUpdate +import org.whispersystems.signalservice.internal.push.SyncMessage.CallLinkUpdate import java.util.concurrent.TimeUnit /** @@ -38,7 +38,7 @@ class RefreshCallLinkDetailsJob private constructor( const val KEY = "RefreshCallLinkDetailsJob" } - override fun serialize(): ByteArray = callLinkUpdate.toByteArray() + override fun serialize(): ByteArray = callLinkUpdate.encode() override fun getFactoryKey(): String = KEY @@ -47,7 +47,7 @@ class RefreshCallLinkDetailsJob private constructor( override fun onRun() { val manager: SignalCallLinkManager = ApplicationDependencies.getSignalCallManager().callLinkManager val credentials = CallLinkCredentials( - linkKeyBytes = callLinkUpdate.rootKey.toByteArray(), + linkKeyBytes = callLinkUpdate.rootKey!!.toByteArray(), adminPassBytes = callLinkUpdate.adminPassKey?.toByteArray() ) @@ -63,7 +63,7 @@ class RefreshCallLinkDetailsJob private constructor( class Factory : Job.Factory { override fun create(parameters: Parameters, serializedData: ByteArray?): RefreshCallLinkDetailsJob { - val callLinkUpdate = CallLinkUpdate.parseFrom(serializedData) + val callLinkUpdate = CallLinkUpdate.ADAPTER.decode(serializedData!!) return RefreshCallLinkDetailsJob(parameters, callLinkUpdate) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ResendMessageJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ResendMessageJob.java index 301a7ad8c4..d3e93b301d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ResendMessageJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ResendMessageJob.java @@ -3,21 +3,18 @@ package org.thoughtcrime.securesms.jobs; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.core.util.ThreadUtil; import org.signal.core.util.logging.Log; import org.signal.libsignal.protocol.SignalProtocolAddress; import org.signal.libsignal.protocol.message.SenderKeyDistributionMessage; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; -import org.thoughtcrime.securesms.database.model.GroupRecord; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.DistributionListRecord; +import org.thoughtcrime.securesms.database.model.GroupRecord; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.groups.GroupId; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; +import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; @@ -30,13 +27,16 @@ import org.whispersystems.signalservice.api.messages.SendMessageResult; import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content; +import org.whispersystems.signalservice.internal.push.Content; +import java.io.IOException; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import okio.ByteString; + /** * Resends a previously-sent message in response to receiving a retry receipt. * @@ -111,7 +111,7 @@ public class ResendMessageJob extends BaseJob { return new JsonJobData.Builder() .putString(KEY_RECIPIENT_ID, recipientId.serialize()) .putLong(KEY_SENT_TIMESTAMP, sentTimestamp) - .putBlobAsString(KEY_CONTENT, content.toByteArray()) + .putBlobAsString(KEY_CONTENT, content.encode()) .putInt(KEY_CONTENT_HINT, contentHint.getType()) .putBoolean(KEY_URGENT, urgent) .putBlobAsString(KEY_GROUP_ID, groupId != null ? groupId.getDecodedId() : null) @@ -169,9 +169,9 @@ public class ResendMessageJob extends BaseJob { } SenderKeyDistributionMessage senderKeyDistributionMessage = messageSender.getOrCreateNewGroupSession(distributionId); - ByteString distributionBytes = ByteString.copyFrom(senderKeyDistributionMessage.serialize()); + ByteString distributionBytes = ByteString.of(senderKeyDistributionMessage.serialize()); - contentToSend = contentToSend.toBuilder().setSenderKeyDistributionMessage(distributionBytes).build(); + contentToSend = contentToSend.newBuilder().senderKeyDistributionMessage(distributionBytes).build(); } SendMessageResult result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.ofNullable(groupId).map(GroupId::getDecodedId), urgent); @@ -204,8 +204,8 @@ public class ResendMessageJob extends BaseJob { Content content; try { - content = Content.parseFrom(data.getStringAsBlob(KEY_CONTENT)); - } catch (InvalidProtocolBufferException e) { + content = Content.ADAPTER.decode(data.getStringAsBlob(KEY_CONTENT)); + } catch (IOException e) { throw new AssertionError(e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob.kt index 57736c9639..b145ba4651 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveRemoteAnnouncementsJob.kt @@ -189,7 +189,7 @@ class RetrieveRemoteAnnouncementsJob private constructor(private val force: Bool .forEach { note -> val title = "${note.translation.title}\n\n" val body = "$title${note.translation.body}" - val bodyRangeList = BodyRangeList.newBuilder() + val bodyRangeList = BodyRangeList.Builder() .addStyle(BodyRangeList.BodyRange.Style.BOLD, 0, note.translation.title.length) if (note.translation.bodyRanges?.isNotEmpty() == true) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java index c99e1a6898..583a5fe21d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java @@ -9,6 +9,7 @@ import com.annimon.stream.Stream; import net.zetetic.database.sqlcipher.SQLiteDatabase; +import org.signal.core.util.Stopwatch; import org.signal.core.util.logging.Log; import org.signal.libsignal.protocol.InvalidKeyException; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; @@ -34,7 +35,6 @@ import org.thoughtcrime.securesms.storage.StorageSyncModels; import org.thoughtcrime.securesms.storage.StorageSyncValidations; import org.thoughtcrime.securesms.storage.StoryDistributionListRecordProcessor; import org.thoughtcrime.securesms.transport.RetryLaterException; -import org.signal.core.util.Stopwatch; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.signalservice.api.SignalServiceAccountManager; @@ -52,7 +52,7 @@ import org.whispersystems.signalservice.api.storage.SignalStorageRecord; import org.whispersystems.signalservice.api.storage.SignalStoryDistributionListRecord; import org.whispersystems.signalservice.api.storage.StorageId; import org.whispersystems.signalservice.api.storage.StorageKey; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.SyncMessage; import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord; import java.io.IOException; @@ -209,7 +209,7 @@ public class StorageSyncJob extends BaseJob { } else { Log.w(TAG, "Failed to decrypt remote storage! Requesting new keys from primary.", e); SignalStore.storageService().clearStorageKeyFromPrimary(); - ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(SignalServiceSyncMessage.forRequest(RequestMessage.forType(SignalServiceProtos.SyncMessage.Request.Type.KEYS)), UnidentifiedAccessUtil.getAccessForSync(context)); + ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(SignalServiceSyncMessage.forRequest(RequestMessage.forType(SyncMessage.Request.Type.KEYS)), UnidentifiedAccessUtil.getAccessForSync(context)); } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt index 26e7d50f8e..ce41c15a34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt @@ -1,8 +1,8 @@ package org.thoughtcrime.securesms.keyvalue -import com.google.protobuf.InvalidProtocolBufferException import org.thoughtcrime.securesms.conversation.colors.ChatColors import org.thoughtcrime.securesms.database.model.databaseprotos.ChatColor +import java.io.IOException internal class ChatColorsValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) { @@ -37,14 +37,14 @@ internal class ChatColorsValues internal constructor(store: KeyValueStore) : Sig var chatColors: ChatColors? get() = getBlob(KEY_CHAT_COLORS, null)?.let { bytes -> try { - ChatColors.forChatColor(chatColorsId, ChatColor.parseFrom(bytes)) - } catch (e: InvalidProtocolBufferException) { + ChatColors.forChatColor(chatColorsId, ChatColor.ADAPTER.decode(bytes)) + } catch (e: IOException) { null } } set(value) { if (value != null) { - putBlob(KEY_CHAT_COLORS, value.serialize().toByteArray()) + putBlob(KEY_CHAT_COLORS, value.serialize().encode()) chatColorsId = value.id } else { remove(KEY_CHAT_COLORS) diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt index 3d7dcc69ab..34d98a0ec7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/DonationsValues.kt @@ -240,7 +240,7 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign fun setExpiredBadge(badge: Badge?) { if (badge != null) { - putBlob(EXPIRED_BADGE, Badges.toDatabaseBadge(badge).toByteArray()) + putBlob(EXPIRED_BADGE, Badges.toDatabaseBadge(badge).encode()) } else { remove(EXPIRED_BADGE) } @@ -249,12 +249,12 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign fun getExpiredBadge(): Badge? { val badgeBytes = getBlob(EXPIRED_BADGE, null) ?: return null - return Badges.fromDatabaseBadge(BadgeList.Badge.parseFrom(badgeBytes)) + return Badges.fromDatabaseBadge(BadgeList.Badge.ADAPTER.decode(badgeBytes)) } fun setExpiredGiftBadge(badge: Badge?) { if (badge != null) { - putBlob(EXPIRED_GIFT_BADGE, Badges.toDatabaseBadge(badge).toByteArray()) + putBlob(EXPIRED_GIFT_BADGE, Badges.toDatabaseBadge(badge).encode()) } else { remove(EXPIRED_GIFT_BADGE) } @@ -263,7 +263,7 @@ internal class DonationsValues internal constructor(store: KeyValueStore) : Sign fun getExpiredGiftBadge(): Badge? { val badgeBytes = getBlob(EXPIRED_GIFT_BADGE, null) ?: return null - return Badges.fromDatabaseBadge(BadgeList.Badge.parseFrom(badgeBytes)) + return Badges.fromDatabaseBadge(BadgeList.Badge.ADAPTER.decode(badgeBytes)) } fun getLastKeepAliveLaunchTime(): Long { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/GroupsV2AuthorizationSignalStoreCache.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/GroupsV2AuthorizationSignalStoreCache.java index 9f92177cef..5fd3692f57 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/GroupsV2AuthorizationSignalStoreCache.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/GroupsV2AuthorizationSignalStoreCache.java @@ -2,9 +2,6 @@ package org.thoughtcrime.securesms.keyvalue; import androidx.annotation.NonNull; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.core.util.logging.Log; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPniResponse; @@ -15,11 +12,15 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.TemporalAuthCred import org.thoughtcrime.securesms.groups.GroupsV2Authorization; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api; +import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.function.Function; + +import okio.ByteString; public final class GroupsV2AuthorizationSignalStoreCache implements GroupsV2Authorization.ValueCache { @@ -76,17 +77,17 @@ public final class GroupsV2AuthorizationSignalStoreCache implements GroupsV2Auth } try { - TemporalAuthCredentialResponses temporalCredentials = TemporalAuthCredentialResponses.parseFrom(credentialBlob); - HashMap result = new HashMap<>(temporalCredentials.getCredentialResponseCount()); + TemporalAuthCredentialResponses temporalCredentials = TemporalAuthCredentialResponses.ADAPTER.decode(credentialBlob); + HashMap result = new HashMap<>(temporalCredentials.credentialResponse.size()); - for (TemporalAuthCredentialResponse credential : temporalCredentials.getCredentialResponseList()) { - result.put(credential.getDate(), factory.apply(credential.getAuthCredentialResponse().toByteArray())); + for (TemporalAuthCredentialResponse credential : temporalCredentials.credentialResponse) { + result.put(credential.date, factory.apply(credential.authCredentialResponse.toByteArray())); } Log.i(TAG, String.format(Locale.US, "Loaded %d credentials from local storage", result.size())); return result; - } catch (InvalidProtocolBufferException | InvalidInputException e) { + } catch (IOException | InvalidInputException e) { throw new AssertionError(e); } } @@ -98,16 +99,18 @@ public final class GroupsV2AuthorizationSignalStoreCache implements GroupsV2Auth } private void write(@NonNull String key, @NonNull Map values) { - TemporalAuthCredentialResponses.Builder builder = TemporalAuthCredentialResponses.newBuilder(); + TemporalAuthCredentialResponses.Builder builder = new TemporalAuthCredentialResponses.Builder(); + List respones = new ArrayList<>(); for (Map.Entry entry : values.entrySet()) { - builder.addCredentialResponse(TemporalAuthCredentialResponse.newBuilder() - .setDate(entry.getKey()) - .setAuthCredentialResponse(ByteString.copyFrom(entry.getValue().serialize()))); + respones.add(new TemporalAuthCredentialResponse.Builder() + .date(entry.getKey()) + .authCredentialResponse(ByteString.of(entry.getValue().serialize())) + .build()); } store.beginWrite() - .putBlob(key, builder.build().toByteArray()) + .putBlob(key, builder.credentialResponse(respones).build().encode()) .commit(); Log.i(TAG, String.format(Locale.US, "Written %d credentials to local storage", values.size())); diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PaymentsValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PaymentsValues.kt index 7476fb02e5..0b5c6c78b5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PaymentsValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PaymentsValues.kt @@ -5,7 +5,6 @@ import androidx.annotation.WorkerThread import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.map -import com.google.protobuf.InvalidProtocolBufferException import com.mobilecoin.lib.Mnemonics import com.mobilecoin.lib.exceptions.BadMnemonicException import org.signal.core.util.logging.Log @@ -23,6 +22,7 @@ import org.thoughtcrime.securesms.storage.StorageSyncHelper import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.api.payments.Money +import java.io.IOException import java.math.BigDecimal import java.util.Arrays import java.util.Currency @@ -292,12 +292,12 @@ internal class PaymentsValues internal constructor(store: KeyValueStore) : Signa } fun mobileCoinLatestFullLedger(): MobileCoinLedgerWrapper { - val blob = store.getBlob(MOB_LEDGER, null) ?: return MobileCoinLedgerWrapper(MobileCoinLedger.getDefaultInstance()) + val blob = store.getBlob(MOB_LEDGER, null) ?: return MobileCoinLedgerWrapper(MobileCoinLedger()) return try { - MobileCoinLedgerWrapper(MobileCoinLedger.parseFrom(blob)) - } catch (e: InvalidProtocolBufferException) { + MobileCoinLedgerWrapper(MobileCoinLedger.ADAPTER.decode(blob)) + } catch (e: IOException) { Log.w(TAG, "Bad cached ledger, clearing", e) - setMobileCoinFullLedger(MobileCoinLedgerWrapper(MobileCoinLedger.getDefaultInstance())) + setMobileCoinFullLedger(MobileCoinLedgerWrapper(MobileCoinLedger())) throw AssertionError(e) } } @@ -351,7 +351,7 @@ internal class PaymentsValues internal constructor(store: KeyValueStore) : Signa .putBoolean(USER_CONFIRMED_MNEMONIC, true) .commit() - liveMobileCoinLedger.postValue(MobileCoinLedgerWrapper(MobileCoinLedger.getDefaultInstance())) + liveMobileCoinLedger.postValue(MobileCoinLedgerWrapper(MobileCoinLedger())) StorageSyncHelper.scheduleSyncForDataChange() return WalletRestoreResult.ENTROPY_CHANGED diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PendingChangeNumberMetadataSerializer.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PendingChangeNumberMetadataSerializer.kt index 4a3b4c841d..ab356d5a98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PendingChangeNumberMetadataSerializer.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PendingChangeNumberMetadataSerializer.kt @@ -7,6 +7,6 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.PendingChangeNum * Serialize [PendingChangeNumberMetadata] */ object PendingChangeNumberMetadataSerializer : ByteSerializer { - override fun serialize(data: PendingChangeNumberMetadata): ByteArray = data.toByteArray() - override fun deserialize(data: ByteArray): PendingChangeNumberMetadata = PendingChangeNumberMetadata.parseFrom(data) + override fun serialize(data: PendingChangeNumberMetadata): ByteArray = data.encode() + override fun deserialize(data: ByteArray): PendingChangeNumberMetadata = PendingChangeNumberMetadata.ADAPTER.decode(data) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValues.java index b182609e90..165ea737ef 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStoreValues.java @@ -3,12 +3,11 @@ package org.thoughtcrime.securesms.keyvalue; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.core.util.ByteSerializer; import org.signal.core.util.StringSerializer; import org.thoughtcrime.securesms.database.model.databaseprotos.SignalStoreList; +import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -69,14 +68,14 @@ abstract class SignalStoreValues { } try { - SignalStoreList signalStoreList = SignalStoreList.parseFrom(blob); + SignalStoreList signalStoreList = SignalStoreList.ADAPTER.decode(blob); - return signalStoreList.getContentsList() + return signalStoreList.contents .stream() .map(serializer::deserialize) .collect(Collectors.toList()); - } catch (InvalidProtocolBufferException e) { + } catch (IOException e) { throw new IllegalArgumentException(e); } } @@ -110,12 +109,12 @@ abstract class SignalStoreValues { } void putList(@NonNull String key, @NonNull List values, @NonNull StringSerializer serializer) { - putBlob(key, SignalStoreList.newBuilder() - .addAllContents(values.stream() - .map(serializer::serialize) - .collect(Collectors.toList())) - .build() - .toByteArray()); + putBlob(key, new SignalStoreList.Builder() + .contents(values.stream() + .map(serializer::serialize) + .collect(Collectors.toList())) + .build() + .encode()); } void remove(@NonNull String key) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/WallpaperValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/WallpaperValues.java index 9b36bbd07e..f5b14c6287 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/WallpaperValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/WallpaperValues.java @@ -6,14 +6,13 @@ import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper; import org.thoughtcrime.securesms.wallpaper.ChatWallpaper; import org.thoughtcrime.securesms.wallpaper.ChatWallpaperFactory; import org.thoughtcrime.securesms.wallpaper.WallpaperStorage; +import java.io.IOException; import java.util.Collections; import java.util.List; @@ -40,12 +39,12 @@ public final class WallpaperValues extends SignalStoreValues { Wallpaper currentWallpaper = getCurrentWallpaper(); Uri currentUri = null; - if (currentWallpaper != null && currentWallpaper.hasFile()) { - currentUri = Uri.parse(currentWallpaper.getFile().getUri()); + if (currentWallpaper != null && currentWallpaper.file_ != null) { + currentUri = Uri.parse(currentWallpaper.file_.uri); } if (wallpaper != null) { - putBlob(KEY_WALLPAPER, wallpaper.serialize().toByteArray()); + putBlob(KEY_WALLPAPER, wallpaper.serialize().encode()); } else { getStore().beginWrite().remove(KEY_WALLPAPER).apply(); } @@ -74,10 +73,10 @@ public final class WallpaperValues extends SignalStoreValues { if (currentWallpaper != null) { putBlob(KEY_WALLPAPER, - currentWallpaper.toBuilder() - .setDimLevelInDarkTheme(enabled ? 0.2f : 0) + currentWallpaper.newBuilder() + .dimLevelInDarkTheme(enabled ? 0.2f : 0) .build() - .toByteArray()); + .encode()); } else { throw new IllegalStateException("No wallpaper currently set!"); } @@ -91,8 +90,8 @@ public final class WallpaperValues extends SignalStoreValues { public @Nullable Uri getWallpaperUri() { Wallpaper currentWallpaper = getCurrentWallpaper(); - if (currentWallpaper != null && currentWallpaper.hasFile()) { - return Uri.parse(currentWallpaper.getFile().getUri()); + if (currentWallpaper != null && currentWallpaper.file_ != null) { + return Uri.parse(currentWallpaper.file_.uri); } else { return null; } @@ -103,8 +102,8 @@ public final class WallpaperValues extends SignalStoreValues { if (serialized != null) { try { - return Wallpaper.parseFrom(serialized); - } catch (InvalidProtocolBufferException e) { + return Wallpaper.ADAPTER.decode(serialized); + } catch (IOException e) { Log.w(TAG, "Invalid proto stored for wallpaper!"); return null; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java b/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java index a300ee3c12..b30c5eb1d6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java @@ -387,9 +387,9 @@ public class LinkPreviewRepository { Log.i(TAG, "Group is not locally available for preview generation, fetching from server"); DecryptedGroupJoinInfo joinInfo = GroupManager.getGroupJoinInfoFromServer(context, groupMasterKey, groupInviteLinkUrl.getPassword()); - String description = getMemberCountDescription(context, joinInfo.getMemberCount()); + String description = getMemberCountDescription(context, joinInfo.memberCount); Optional thumbnail = Optional.empty(); - byte[] avatarBytes = AvatarGroupsV2DownloadJob.downloadGroupAvatarBytes(context, groupMasterKey, joinInfo.getAvatar()); + byte[] avatarBytes = AvatarGroupsV2DownloadJob.downloadGroupAvatarBytes(context, groupMasterKey, joinInfo.avatar); if (avatarBytes != null) { Bitmap bitmap = BitmapFactory.decodeByteArray(avatarBytes, 0, avatarBytes.length); @@ -399,7 +399,7 @@ public class LinkPreviewRepository { if (bitmap != null) bitmap.recycle(); } - callback.onSuccess(new LinkPreview(groupUrl, joinInfo.getTitle(), description, 0, thumbnail)); + callback.onSuccess(new LinkPreview(groupUrl, joinInfo.title, description, 0, thumbnail)); } } catch (ExecutionException | InterruptedException | IOException | VerificationFailedException e) { Log.w(TAG, "Failed to fetch group link preview.", e); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivityResult.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivityResult.kt index 10219168eb..4930449e03 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivityResult.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivityResult.kt @@ -53,13 +53,13 @@ object BodyRangeListParceler : Parceler { override fun create(parcel: Parcel): BodyRangeList? { val data: ByteArray? = ParcelUtil.readByteArray(parcel) return if (data != null) { - BodyRangeList.parseFrom(data) + BodyRangeList.ADAPTER.decode(data) } else { null } } override fun BodyRangeList?.write(parcel: Parcel, flags: Int) { - ParcelUtil.writeByteArray(parcel, this?.toByteArray()) + ParcelUtil.writeByteArray(parcel, this?.encode()) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt index d8b8265ec6..8ffa1f3cdb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt @@ -96,7 +96,7 @@ class TextStoryPostSendRepository { } private fun serializeTextStoryState(textStoryPostCreationState: TextStoryPostCreationState): String { - val builder = StoryTextPost.newBuilder() + val builder = StoryTextPost.Builder() builder.body = textStoryPostCreationState.body.toString() builder.background = textStoryPostCreationState.backgroundColor.serialize() @@ -110,6 +110,6 @@ class TextStoryPostSendRepository { builder.textBackgroundColor = textStoryPostCreationState.textBackgroundColor builder.textForegroundColor = textStoryPostCreationState.textForegroundColor - return Base64.encodeBytes(builder.build().toByteArray()) + return Base64.encodeBytes(builder.build().encode()) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java index 42787a3eab..8c7f9f740c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java @@ -68,7 +68,7 @@ public final class MessageRequestRepository { onGroupInfoLoaded.accept(groupRecord.map(record -> { if (record.isV2Group()) { DecryptedGroup decryptedGroup = record.requireV2GroupProperties().getDecryptedGroup(); - return new GroupInfo(decryptedGroup.getMembersCount(), decryptedGroup.getPendingMembersCount(), decryptedGroup.getDescription()); + return new GroupInfo(decryptedGroup.members.size(), decryptedGroup.pendingMembers.size(), decryptedGroup.description); } else { return new GroupInfo(record.getMembers().size(), 0, ""); } @@ -85,7 +85,7 @@ public final class MessageRequestRepository { if (groupRecord.isPresent()) { if (groupRecord.get().isV2Group()) { DecryptedGroup decryptedGroup = groupRecord.get().requireV2GroupProperties().getDecryptedGroup(); - groupInfo = new GroupInfo(decryptedGroup.getMembersCount(), decryptedGroup.getPendingMembersCount(), decryptedGroup.getDescription()); + groupInfo = new GroupInfo(decryptedGroup.members.size(), decryptedGroup.pendingMembers.size(), decryptedGroup.description); } else { groupInfo = new GroupInfo(groupRecord.get().getMembers().size(), 0, ""); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt index b7d889a2ea..3873c05571 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt @@ -4,6 +4,7 @@ import org.signal.ringrtc.CallId import org.thoughtcrime.securesms.database.model.IdentityRecord import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.log +import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.warn import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.ringrtc.RemotePeer @@ -18,49 +19,56 @@ import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata import org.whispersystems.signalservice.api.messages.calls.HangupMessage import org.whispersystems.signalservice.api.messages.calls.OfferMessage import org.whispersystems.signalservice.api.push.ServiceId -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.CallMessage.Offer -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.CallMessage.Opaque -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.CallMessage +import org.whispersystems.signalservice.internal.push.CallMessage.Offer +import org.whispersystems.signalservice.internal.push.CallMessage.Opaque +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope +import kotlin.time.Duration.Companion.milliseconds object CallMessageProcessor { fun process( senderRecipient: Recipient, envelope: Envelope, - content: SignalServiceProtos.Content, + content: Content, metadata: EnvelopeMetadata, serverDeliveredTimestamp: Long ) { - val callMessage = content.callMessage + val callMessage = content.callMessage!! when { - callMessage.hasOffer() -> handleCallOfferMessage(envelope, metadata, callMessage.offer, senderRecipient.id, serverDeliveredTimestamp, callMessage.multiRing) - callMessage.hasAnswer() -> handleCallAnswerMessage(envelope, metadata, callMessage.answer, senderRecipient.id, callMessage.multiRing) - callMessage.iceUpdateList.isNotEmpty() -> handleCallIceUpdateMessage(envelope, metadata, callMessage.iceUpdateList, senderRecipient.id) - callMessage.hasHangup() || callMessage.hasLegacyHangup() -> { - val hangup = if (callMessage.hasHangup()) callMessage.hangup else callMessage.legacyHangup - handleCallHangupMessage(envelope, metadata, hangup, senderRecipient.id) + callMessage.offer != null -> handleCallOfferMessage(envelope, metadata, callMessage.offer!!, senderRecipient.id, serverDeliveredTimestamp) + callMessage.answer != null -> handleCallAnswerMessage(envelope, metadata, callMessage.answer!!, senderRecipient.id) + callMessage.iceUpdate.isNotEmpty() -> handleCallIceUpdateMessage(envelope, metadata, callMessage.iceUpdate, senderRecipient.id) + callMessage.hangup != null || callMessage.legacyHangup != null -> { + handleCallHangupMessage(envelope, metadata, callMessage.hangup ?: callMessage.legacyHangup, senderRecipient.id) } - callMessage.hasBusy() -> handleCallBusyMessage(envelope, metadata, callMessage.busy, senderRecipient.id) - callMessage.hasOpaque() -> handleCallOpaqueMessage(envelope, metadata, callMessage.opaque, senderRecipient.requireAci(), serverDeliveredTimestamp) + callMessage.busy != null -> handleCallBusyMessage(envelope, metadata, callMessage.busy!!, senderRecipient.id) + callMessage.opaque != null -> handleCallOpaqueMessage(envelope, metadata, callMessage.opaque!!, senderRecipient.requireAci(), serverDeliveredTimestamp) } } - private fun handleCallOfferMessage(envelope: Envelope, metadata: EnvelopeMetadata, offer: Offer, senderRecipientId: RecipientId, serverDeliveredTimestamp: Long, multiRing: Boolean) { - log(envelope.timestamp, "handleCallOfferMessage...") + private fun handleCallOfferMessage(envelope: Envelope, metadata: EnvelopeMetadata, offer: Offer, senderRecipientId: RecipientId, serverDeliveredTimestamp: Long) { + log(envelope.timestamp!!, "handleCallOfferMessage...") - val remotePeer = RemotePeer(senderRecipientId, CallId(offer.id)) + val offerId = if (offer.id != null && offer.type != null && ((offer.opaque != null) xor (offer.sdp != null))) { + offer.id!! + } else { + warn(envelope.timestamp!!, "Invalid offer, missing id/type, or invalid combination of opaque/sdp") + return + } + + val remotePeer = RemotePeer(senderRecipientId, CallId(offerId)) val remoteIdentityKey = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecord(senderRecipientId).map { (_, identityKey): IdentityRecord -> identityKey.serialize() }.get() ApplicationDependencies.getSignalCallManager() .receivedOffer( CallMetadata(remotePeer, metadata.sourceDeviceId), - offer.toCallOfferMetadata(), + OfferMetadata(offer.opaque?.toByteArray(), offer.sdp, OfferMessage.Type.fromProto(offer.type!!)), ReceivedOfferMetadata( remoteIdentityKey, - envelope.serverTimestamp, - serverDeliveredTimestamp, - multiRing + envelope.serverTimestamp!!, + serverDeliveredTimestamp ) ) } @@ -68,94 +76,119 @@ object CallMessageProcessor { private fun handleCallAnswerMessage( envelope: Envelope, metadata: EnvelopeMetadata, - answer: SignalServiceProtos.CallMessage.Answer, - senderRecipientId: RecipientId, - multiRing: Boolean + answer: CallMessage.Answer, + senderRecipientId: RecipientId ) { - log(envelope.timestamp, "handleCallAnswerMessage...") + log(envelope.timestamp!!, "handleCallAnswerMessage...") - val remotePeer = RemotePeer(senderRecipientId, CallId(answer.id)) + val answerId = if (answer.id != null && ((answer.opaque != null) xor (answer.sdp != null))) { + answer.id!! + } else { + warn(envelope.timestamp!!, "Invalid answer, missing id") + return + } + + val remotePeer = RemotePeer(senderRecipientId, CallId(answerId)) val remoteIdentityKey = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecord(senderRecipientId).map { (_, identityKey): IdentityRecord -> identityKey.serialize() }.get() ApplicationDependencies.getSignalCallManager() .receivedAnswer( CallMetadata(remotePeer, metadata.sourceDeviceId), - AnswerMetadata(if (answer.hasOpaque()) answer.opaque.toByteArray() else null, if (answer.hasSdp()) answer.sdp else null), - ReceivedAnswerMetadata(remoteIdentityKey, multiRing) + AnswerMetadata(answer.opaque?.toByteArray(), answer.sdp), + ReceivedAnswerMetadata(remoteIdentityKey) ) } private fun handleCallIceUpdateMessage( envelope: Envelope, metadata: EnvelopeMetadata, - iceUpdateList: MutableList, + iceUpdateList: List, senderRecipientId: RecipientId ) { - log(envelope.timestamp, "handleCallIceUpdateMessage... " + iceUpdateList.size) + log(envelope.timestamp!!, "handleCallIceUpdateMessage... " + iceUpdateList.size) val iceCandidates: MutableList = ArrayList(iceUpdateList.size) var callId: Long = -1 iceUpdateList - .filter { it.hasOpaque() } + .filter { it.opaque != null && it.id != null } .forEach { iceUpdate -> - iceCandidates += iceUpdate.opaque.toByteArray() - callId = iceUpdate.id + iceCandidates += iceUpdate.opaque!!.toByteArray() + callId = iceUpdate.id!! } - val remotePeer = RemotePeer(senderRecipientId, CallId(callId)) - ApplicationDependencies.getSignalCallManager() - .receivedIceCandidates( - CallMetadata(remotePeer, metadata.sourceDeviceId), - iceCandidates - ) + if (iceCandidates.isNotEmpty()) { + val remotePeer = RemotePeer(senderRecipientId, CallId(callId)) + ApplicationDependencies.getSignalCallManager() + .receivedIceCandidates( + CallMetadata(remotePeer, metadata.sourceDeviceId), + iceCandidates + ) + } else { + warn(envelope.timestamp!!, "Invalid ice updates, all missing opaque and/or call id") + } } private fun handleCallHangupMessage( envelope: Envelope, metadata: EnvelopeMetadata, - hangup: SignalServiceProtos.CallMessage.Hangup, + hangup: CallMessage.Hangup?, senderRecipientId: RecipientId ) { - log(envelope.timestamp, "handleCallHangupMessage") + log(envelope.timestamp!!, "handleCallHangupMessage") - val remotePeer = RemotePeer(senderRecipientId, CallId(hangup.id)) + val (hangupId, hangupDeviceId) = if (hangup?.id != null && hangup.deviceId != null) { + hangup.id!! to hangup.deviceId!! + } else { + warn(envelope.timestamp!!, "Invalid hangup, null message or missing id/deviceId") + return + } + + val remotePeer = RemotePeer(senderRecipientId, CallId(hangupId)) ApplicationDependencies.getSignalCallManager() .receivedCallHangup( CallMetadata(remotePeer, metadata.sourceDeviceId), - HangupMetadata(HangupMessage.Type.fromProto(hangup.type), hangup.deviceId) + HangupMetadata(HangupMessage.Type.fromProto(hangup.type), hangupDeviceId) ) } - private fun handleCallBusyMessage(envelope: Envelope, metadata: EnvelopeMetadata, busy: SignalServiceProtos.CallMessage.Busy, senderRecipientId: RecipientId) { - log(envelope.timestamp, "handleCallBusyMessage") + private fun handleCallBusyMessage(envelope: Envelope, metadata: EnvelopeMetadata, busy: CallMessage.Busy, senderRecipientId: RecipientId) { + log(envelope.timestamp!!, "handleCallBusyMessage") - val remotePeer = RemotePeer(senderRecipientId, CallId(busy.id)) + val busyId = if (busy.id != null) { + busy.id!! + } else { + warn(envelope.timestamp!!, "Invalid busy, missing call id") + return + } + + val remotePeer = RemotePeer(senderRecipientId, CallId(busyId)) ApplicationDependencies.getSignalCallManager().receivedCallBusy(CallMetadata(remotePeer, metadata.sourceDeviceId)) } private fun handleCallOpaqueMessage(envelope: Envelope, metadata: EnvelopeMetadata, opaque: Opaque, senderServiceId: ServiceId, serverDeliveredTimestamp: Long) { - log(envelope.timestamp.toString(), "handleCallOpaqueMessage") + log(envelope.timestamp!!, "handleCallOpaqueMessage") + + val data = if (opaque.data_ != null) { + opaque.data_!!.toByteArray() + } else { + warn(envelope.timestamp!!, "Invalid opaque message, null data") + return + } var messageAgeSeconds: Long = 0 if (envelope.serverTimestamp in 1..serverDeliveredTimestamp) { - messageAgeSeconds = (serverDeliveredTimestamp - envelope.serverTimestamp) / 1000 + messageAgeSeconds = (serverDeliveredTimestamp - envelope.serverTimestamp!!).milliseconds.inWholeSeconds } ApplicationDependencies.getSignalCallManager() .receivedOpaqueMessage( OpaqueMessageMetadata( senderServiceId.rawUuid, - opaque.data.toByteArray(), + data, metadata.sourceDeviceId, messageAgeSeconds ) ) } - - private fun Offer.toCallOfferMetadata(): OfferMetadata { - val sdp = if (hasSdp()) sdp else null - val opaque = if (hasOpaque()) opaque else null - return OfferMetadata(opaque?.toByteArray(), sdp, OfferMessage.Type.fromProto(type)) - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt index 707e495814..de451cb1e5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt @@ -1,9 +1,10 @@ package org.thoughtcrime.securesms.messages +import ProtoUtil.isNotEmpty import android.content.Context import android.text.TextUtils -import com.google.protobuf.ByteString import com.mobilecoin.lib.exceptions.SerializationException +import okio.ByteString.Companion.toByteString import org.signal.core.util.Hex import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.logging.Log @@ -36,6 +37,7 @@ import org.thoughtcrime.securesms.database.model.ParentStoryId import org.thoughtcrime.securesms.database.model.ParentStoryId.DirectReply import org.thoughtcrime.securesms.database.model.ParentStoryId.GroupReply import org.thoughtcrime.securesms.database.model.ReactionRecord +import org.thoughtcrime.securesms.database.model.StickerRecord import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge import org.thoughtcrime.securesms.database.model.toBodyRangeList @@ -59,6 +61,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.debug import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.log import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.warn +import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.expireTimerDuration import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.groupMasterKey import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.hasGroupContext import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.hasRemoteDelete @@ -98,12 +101,12 @@ import org.whispersystems.signalservice.api.payments.Money import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.util.OptionalUtil.asOptional -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2 -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Preview +import org.whispersystems.signalservice.internal.push.BodyRange +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.GroupContextV2 +import org.whispersystems.signalservice.internal.push.Preview import java.security.SecureRandom import java.util.Optional import java.util.UUID @@ -125,13 +128,13 @@ object DataMessageProcessor { earlyMessageCacheEntry: EarlyMessageCacheEntry?, localMetrics: SignalLocalMetrics.MessageReceive? ) { - val message: DataMessage = content.dataMessage - val groupSecretParams = if (message.hasGroupContext) GroupSecretParams.deriveFromMasterKey(message.groupV2.groupMasterKey) else null + val message: DataMessage = content.dataMessage!! + val groupSecretParams = if (message.hasGroupContext) GroupSecretParams.deriveFromMasterKey(message.groupV2!!.groupMasterKey) else null val groupId: GroupId.V2? = if (groupSecretParams != null) GroupId.v2(groupSecretParams.publicParams.groupIdentifier) else null var groupProcessResult: MessageContentProcessor.Gv2PreProcessResult? = null if (groupId != null) { - groupProcessResult = MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp, content, metadata, groupId, message.groupV2, senderRecipient, groupSecretParams) + groupProcessResult = MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp!!, content, metadata, groupId, message.groupV2!!, senderRecipient, groupSecretParams) if (groupProcessResult == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { return } @@ -140,20 +143,20 @@ object DataMessageProcessor { var messageId: MessageId? = null when { - message.isInvalid -> handleInvalidMessage(context, senderRecipient.id, metadata.sourceDeviceId, groupId, envelope.timestamp) + message.isInvalid -> handleInvalidMessage(context, senderRecipient.id, metadata.sourceDeviceId, groupId, envelope.timestamp!!) message.isEndSession -> messageId = handleEndSessionMessage(context, senderRecipient.id, envelope, metadata) - message.isExpirationUpdate -> messageId = handleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient.id, groupId, message.expireTimer.seconds, receivedTime, false) + message.isExpirationUpdate -> messageId = handleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient.id, groupId, message.expireTimerDuration, receivedTime, false) message.isStoryReaction -> messageId = handleStoryReaction(context, envelope, metadata, message, senderRecipient.id, groupId) - message.hasReaction() -> messageId = handleReaction(context, envelope, message, senderRecipient.id, earlyMessageCacheEntry) + message.reaction != null -> messageId = handleReaction(context, envelope, message, senderRecipient.id, earlyMessageCacheEntry) message.hasRemoteDelete -> messageId = handleRemoteDelete(context, envelope, message, senderRecipient.id, earlyMessageCacheEntry) message.isPaymentActivationRequest -> messageId = handlePaymentActivation(envelope, metadata, message, senderRecipient.id, receivedTime, isActivatePaymentsRequest = true, isPaymentsActivated = false) message.isPaymentActivated -> messageId = handlePaymentActivation(envelope, metadata, message, senderRecipient.id, receivedTime, isActivatePaymentsRequest = false, isPaymentsActivated = true) - message.hasPayment() -> messageId = handlePayment(context, envelope, metadata, message, senderRecipient.id, receivedTime) - message.hasStoryContext() -> messageId = handleStoryReply(context, envelope, metadata, message, senderRecipient, groupId, receivedTime) - message.hasGiftBadge() -> messageId = handleGiftMessage(context, envelope, metadata, message, senderRecipient, threadRecipient.id, receivedTime) + message.payment != null -> messageId = handlePayment(context, envelope, metadata, message, senderRecipient.id, receivedTime) + message.storyContext != null -> messageId = handleStoryReply(context, envelope, metadata, message, senderRecipient, groupId, receivedTime) + message.giftBadge != null -> messageId = handleGiftMessage(context, envelope, metadata, message, senderRecipient, threadRecipient.id, receivedTime) message.isMediaMessage -> messageId = handleMediaMessage(context, envelope, metadata, message, senderRecipient, threadRecipient, groupId, receivedTime, localMetrics) - message.hasBody() -> messageId = handleTextMessage(context, envelope, metadata, message, senderRecipient, threadRecipient, groupId, receivedTime, localMetrics) - message.hasGroupCallUpdate() -> handleGroupCallUpdateMessage(envelope, message, senderRecipient.id, groupId) + message.body != null -> messageId = handleTextMessage(context, envelope, metadata, message, senderRecipient, threadRecipient, groupId, receivedTime, localMetrics) + message.groupCallUpdate != null -> handleGroupCallUpdateMessage(envelope, message, senderRecipient.id, groupId) } if (groupId != null) { @@ -162,12 +165,12 @@ object DataMessageProcessor { else -> SignalDatabase.groups.isUnknownGroup(groupId) } if (unknownGroup) { - handleUnknownGroupMessage(envelope.timestamp, message.groupV2) + handleUnknownGroupMessage(envelope.timestamp!!, message.groupV2!!) } } - if (message.hasProfileKey()) { - handleProfileKey(envelope.timestamp, message.profileKey.toByteArray(), senderRecipient) + if (message.profileKey.isNotEmpty()) { + handleProfileKey(envelope.timestamp!!, message.profileKey!!.toByteArray(), senderRecipient) } if (groupId == null && senderRecipient.hiddenState == HiddenState.HIDDEN) { @@ -175,7 +178,7 @@ object DataMessageProcessor { } if (metadata.sealedSender && messageId != null) { - SignalExecutors.BOUNDED.execute { ApplicationDependencies.getJobManager().add(SendDeliveryReceiptJob(senderRecipient.id, message.timestamp, messageId)) } + SignalExecutors.BOUNDED.execute { ApplicationDependencies.getJobManager().add(SendDeliveryReceiptJob(senderRecipient.id, message.timestamp!!, messageId)) } } else if (!metadata.sealedSender) { if (RecipientUtil.shouldHaveProfileKey(threadRecipient)) { Log.w(MessageContentProcessor.TAG, "Received an unsealed sender message from " + senderRecipient.id + ", but they should already have our profile key. Correcting.") @@ -260,13 +263,13 @@ object DataMessageProcessor { envelope: Envelope, metadata: EnvelopeMetadata ): MessageId? { - log(envelope.timestamp, "End session message.") + log(envelope.timestamp!!, "End session message.") val incomingTextMessage = IncomingTextMessage( senderRecipientId, metadata.sourceDeviceId, - envelope.timestamp, - envelope.serverTimestamp, + envelope.timestamp!!, + envelope.serverTimestamp!!, System.currentTimeMillis(), "", Optional.empty(), @@ -302,23 +305,23 @@ object DataMessageProcessor { receivedTime: Long, sideEffect: Boolean ): MessageId? { - log(envelope.timestamp, "Expiration update. Side effect: $sideEffect") + log(envelope.timestamp!!, "Expiration update. Side effect: $sideEffect") if (groupId != null) { - warn(envelope.timestamp, "Expiration update received for GV2. Ignoring.") + warn(envelope.timestamp!!, "Expiration update received for GV2. Ignoring.") return null } if (SignalDatabase.recipients.getExpiresInSeconds(threadRecipientId) == expiresIn.inWholeSeconds) { - log(envelope.timestamp, "No change in message expiry for group. Ignoring.") + log(envelope.timestamp!!, "No change in message expiry for group. Ignoring.") return null } try { val mediaMessage = IncomingMediaMessage( from = senderRecipientId, - sentTimeMillis = envelope.timestamp - if (sideEffect) 1 else 0, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!! - if (sideEffect) 1 else 0, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, expiresIn = expiresIn.inWholeMilliseconds, isExpirationUpdate = true, @@ -354,7 +357,7 @@ object DataMessageProcessor { receivedTime: Long ) { if (threadRecipient.expiresInSeconds.toLong() != expiresIn.inWholeSeconds) { - warn(envelope.timestamp, "Message expire time didn't match thread expire time. Handling timer update.") + warn(envelope.timestamp!!, "Message expire time didn't match thread expire time. Handling timer update.") handleExpirationUpdate(envelope, metadata, senderRecipientId, threadRecipient.id, groupId, expiresIn, receivedTime, true) } } @@ -368,16 +371,18 @@ object DataMessageProcessor { senderRecipientId: RecipientId, groupId: GroupId.V2? ): MessageId? { - log(envelope.timestamp, "Story reaction.") + log(envelope.timestamp!!, "Story reaction.") + + val storyContext = message.storyContext!! + val emoji = message.reaction!!.emoji - val emoji = message.reaction.emoji if (!EmojiUtil.isEmoji(emoji)) { - warn(envelope.timestamp, "Story reaction text is not a valid emoji! Ignoring the message.") + warn(envelope.timestamp!!, "Story reaction text is not a valid emoji! Ignoring the message.") return null } - val authorServiceId: ServiceId = ServiceId.parseOrThrow(message.storyContext.authorAci) - val sentTimestamp = message.storyContext.sentTimestamp + val authorServiceId: ServiceId = ServiceId.parseOrThrow(storyContext.authorAci!!) + val sentTimestamp = storyContext.sentTimestamp!! SignalDatabase.messages.beginTransaction() return try { @@ -403,20 +408,20 @@ object DataMessageProcessor { parentStoryId = DirectReply(storyId) quoteModel = QuoteModel(sentTimestamp, authorRecipientId, displayText, false, story.slideDeck.asAttachments(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges) - expiresIn = message.expireTimer.seconds + expiresIn = message.expireTimerDuration } else { - warn(envelope.timestamp, "Story has reactions disabled. Dropping reaction.") + warn(envelope.timestamp!!, "Story has reactions disabled. Dropping reaction.") return null } } catch (e: NoSuchMessageException) { - warn(envelope.timestamp, "Couldn't find story for reaction.", e) + warn(envelope.timestamp!!, "Couldn't find story for reaction.", e) return null } val mediaMessage = IncomingMediaMessage( from = senderRecipientId, - sentTimeMillis = envelope.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = System.currentTimeMillis(), parentStoryId = parentStoryId, isStoryReaction = true, @@ -445,7 +450,7 @@ object DataMessageProcessor { null } } else { - warn(envelope.timestamp, "Failed to insert story reaction") + warn(envelope.timestamp!!, "Failed to insert story reaction") null } } catch (e: MmsException) { @@ -463,27 +468,29 @@ object DataMessageProcessor { senderRecipientId: RecipientId, earlyMessageCacheEntry: EarlyMessageCacheEntry? ): MessageId? { - log(envelope.timestamp, "Handle reaction for message " + message.reaction.targetSentTimestamp) + val reaction: DataMessage.Reaction = message.reaction!! - val emoji: String = message.reaction.emoji - val isRemove: Boolean = message.reaction.remove - val targetAuthorServiceId: ServiceId = ServiceId.parseOrThrow(message.reaction.targetAuthorAci) - val targetSentTimestamp = message.reaction.targetSentTimestamp + log(envelope.timestamp!!, "Handle reaction for message " + reaction.targetSentTimestamp!!) + + val emoji: String? = reaction.emoji + val isRemove: Boolean = reaction.remove ?: false + val targetAuthorServiceId: ServiceId = ServiceId.parseOrThrow(reaction.targetAuthorAci!!) + val targetSentTimestamp: Long = reaction.targetSentTimestamp!! if (targetAuthorServiceId.isUnknown) { - warn(envelope.timestamp, "Reaction was to an unknown UUID! Ignoring the message.") + warn(envelope.timestamp!!, "Reaction was to an unknown UUID! Ignoring the message.") return null } if (!EmojiUtil.isEmoji(emoji)) { - warn(envelope.timestamp, "Reaction text is not a valid emoji! Ignoring the message.") + warn(envelope.timestamp!!, "Reaction text is not a valid emoji! Ignoring the message.") return null } val targetAuthor = Recipient.externalPush(targetAuthorServiceId) val targetMessage = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) if (targetMessage == null) { - warn(envelope.timestamp, "[handleReaction] Could not find matching message! Putting it in the early message cache. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) + warn(envelope.timestamp!!, "[handleReaction] Could not find matching message! Putting it in the early message cache. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) if (earlyMessageCacheEntry != null) { ApplicationDependencies.getEarlyMessageCache().store(targetAuthor.id, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -492,25 +499,25 @@ object DataMessageProcessor { } if (targetMessage.isRemoteDelete) { - warn(envelope.timestamp, "[handleReaction] Found a matching message, but it's flagged as remotely deleted. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) + warn(envelope.timestamp!!, "[handleReaction] Found a matching message, but it's flagged as remotely deleted. timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) return null } val targetThread = SignalDatabase.threads.getThreadRecord(targetMessage.threadId) if (targetThread == null) { - warn(envelope.timestamp, "[handleReaction] Could not find a thread for the message! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) + warn(envelope.timestamp!!, "[handleReaction] Could not find a thread for the message! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) return null } val targetThreadRecipientId = targetThread.recipient.id val groupRecord = SignalDatabase.groups.getGroup(targetThreadRecipientId).orNull() if (groupRecord != null && !groupRecord.members.contains(senderRecipientId)) { - warn(envelope.timestamp, "[handleReaction] Reaction author is not in the group! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) + warn(envelope.timestamp!!, "[handleReaction] Reaction author is not in the group! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) return null } if (groupRecord == null && senderRecipientId != targetThreadRecipientId && Recipient.self().id != senderRecipientId) { - warn(envelope.timestamp, "[handleReaction] Reaction author is not a part of the 1:1 thread! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) + warn(envelope.timestamp!!, "[handleReaction] Reaction author is not a part of the 1:1 thread! timestamp: " + targetSentTimestamp + " author: " + targetAuthor.id) return null } @@ -520,7 +527,7 @@ object DataMessageProcessor { SignalDatabase.reactions.deleteReaction(targetMessageId, senderRecipientId) ApplicationDependencies.getMessageNotifier().updateNotification(context) } else { - val reactionRecord = ReactionRecord(emoji, senderRecipientId, message.timestamp, System.currentTimeMillis()) + val reactionRecord = ReactionRecord(emoji!!, senderRecipientId, message.timestamp!!, System.currentTimeMillis()) SignalDatabase.reactions.addReaction(targetMessageId, reactionRecord) ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.fromMessageRecord(targetMessage), false) } @@ -529,12 +536,14 @@ object DataMessageProcessor { } fun handleRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipientId: RecipientId, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? { - log(envelope.timestamp, "Remote delete for message ${message.delete.targetSentTimestamp}") + val delete = message.delete!! - val targetSentTimestamp: Long = message.delete.targetSentTimestamp + log(envelope.timestamp!!, "Remote delete for message ${delete.targetSentTimestamp}") + + val targetSentTimestamp: Long = delete.targetSentTimestamp!! val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, senderRecipientId) - return if (targetMessage != null && MessageConstraintsUtil.isValidRemoteDeleteReceive(targetMessage, senderRecipientId, envelope.serverTimestamp)) { + return if (targetMessage != null && MessageConstraintsUtil.isValidRemoteDeleteReceive(targetMessage, senderRecipientId, envelope.serverTimestamp!!)) { SignalDatabase.messages.markAsRemoteDelete(targetMessage) if (targetMessage.isStory()) { SignalDatabase.messages.deleteRemotelyDeletedStory(targetMessage.id) @@ -544,7 +553,7 @@ object DataMessageProcessor { MessageId(targetMessage.id) } else if (targetMessage == null) { - warn(envelope.timestamp, "[handleRemoteDelete] Could not find matching message! timestamp: $targetSentTimestamp author: $senderRecipientId") + warn(envelope.timestamp!!, "[handleRemoteDelete] Could not find matching message! timestamp: $targetSentTimestamp author: $senderRecipientId") if (earlyMessageCacheEntry != null) { ApplicationDependencies.getEarlyMessageCache().store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() @@ -552,7 +561,7 @@ object DataMessageProcessor { null } else { - warn(envelope.timestamp, "[handleRemoteDelete] Invalid remote delete! deleteTime: ${envelope.serverTimestamp}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}") + warn(envelope.timestamp!!, "[handleRemoteDelete] Invalid remote delete! deleteTime: ${envelope.serverTimestamp!!}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}") null } } @@ -572,14 +581,14 @@ object DataMessageProcessor { isActivatePaymentsRequest: Boolean, isPaymentsActivated: Boolean ): MessageId? { - log(envelope.timestamp, "Payment activation request: $isActivatePaymentsRequest activated: $isPaymentsActivated") + log(envelope.timestamp!!, "Payment activation request: $isActivatePaymentsRequest activated: $isPaymentsActivated") try { val mediaMessage = IncomingMediaMessage( from = senderRecipientId, - sentTimeMillis = envelope.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, - expiresIn = message.expireTimer.seconds.inWholeMilliseconds, + expiresIn = message.expireTimerDuration.inWholeMilliseconds, isUnidentified = metadata.sealedSender, serverGuid = envelope.serverGuid, isActivatePaymentsRequest = isActivatePaymentsRequest, @@ -606,14 +615,14 @@ object DataMessageProcessor { senderRecipientId: RecipientId, receivedTime: Long ): MessageId? { - log(envelope.timestamp, "Payment message.") + log(envelope.timestamp!!, "Payment message.") - if (!message.payment.notification.mobileCoin.hasReceipt()) { - warn(envelope.timestamp, "Ignoring payment message without notification") + if (message.payment?.notification?.mobileCoin?.receipt == null) { + warn(envelope.timestamp!!, "Ignoring payment message without notification") return null } - val paymentNotification = message.payment.notification + val paymentNotification = message.payment!!.notification!! val uuid = UUID.randomUUID() val queue = "Payment_" + PushProcessMessageJob.getQueueName(senderRecipientId) @@ -621,21 +630,21 @@ object DataMessageProcessor { SignalDatabase.payments.createIncomingPayment( uuid, senderRecipientId, - message.timestamp, - paymentNotification.note, + message.timestamp!!, + paymentNotification.note ?: "", Money.MobileCoin.ZERO, Money.MobileCoin.ZERO, - paymentNotification.mobileCoin.receipt.toByteArray(), + paymentNotification.mobileCoin!!.receipt!!.toByteArray(), true ) val mediaMessage = IncomingMediaMessage( from = senderRecipientId, body = uuid.toString(), - sentTimeMillis = envelope.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, - expiresIn = message.expireTimer.seconds.inWholeMilliseconds, + expiresIn = message.expireTimerDuration.inWholeMilliseconds, isUnidentified = metadata.sealedSender, serverGuid = envelope.serverGuid, isPushMessage = true, @@ -649,9 +658,9 @@ object DataMessageProcessor { return messageId } } catch (e: PublicKeyConflictException) { - warn(envelope.timestamp, "Ignoring payment with public key already in database") + warn(envelope.timestamp!!, "Ignoring payment with public key already in database") } catch (e: SerializationException) { - warn(envelope.timestamp, "Ignoring payment with bad data.", e) + warn(envelope.timestamp!!, "Ignoring payment with bad data.", e) } catch (e: MmsException) { throw StorageFailedException(e, metadata.sourceServiceId.toString(), metadata.sourceDeviceId) } finally { @@ -676,10 +685,16 @@ object DataMessageProcessor { groupId: GroupId.V2?, receivedTime: Long ): MessageId? { - log(envelope.timestamp, "Story reply.") + log(envelope.timestamp!!, "Story reply.") - val authorServiceId: ServiceId = ServiceId.parseOrThrow(message.storyContext.authorAci) - val sentTimestamp = message.storyContext.sentTimestamp + val storyContext: DataMessage.StoryContext = message.storyContext!! + val authorServiceId: ServiceId = ServiceId.parseOrThrow(storyContext.authorAci!!) + val sentTimestamp: Long = if (storyContext.sentTimestamp != null) { + storyContext.sentTimestamp!! + } else { + warn(envelope.timestamp!!, "Invalid story reply, missing sentTimestamp") + return null + } SignalDatabase.messages.beginTransaction() return try { @@ -708,7 +723,7 @@ object DataMessageProcessor { threadRecipient = senderRecipient } - handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimer.seconds, receivedTime) + handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimerDuration, receivedTime) if (message.hasGroupContext) { parentStoryId = GroupReply(storyMessageId.id) @@ -723,22 +738,22 @@ object DataMessageProcessor { } quoteModel = QuoteModel(sentTimestamp, storyAuthorRecipientId, displayText, false, story.slideDeck.asAttachments(), emptyList(), QuoteModel.Type.NORMAL, bodyRanges) - expiresInMillis = message.expireTimer.seconds + expiresInMillis = message.expireTimerDuration } else { - warn(envelope.timestamp, "Story has replies disabled. Dropping reply.") + warn(envelope.timestamp!!, "Story has replies disabled. Dropping reply.") return null } } catch (e: NoSuchMessageException) { - warn(envelope.timestamp, "Couldn't find story for reply.", e) + warn(envelope.timestamp!!, "Couldn't find story for reply.", e) return null } - val bodyRanges: BodyRangeList? = message.bodyRangesList.filter { it.hasStyle() }.toList().toBodyRangeList() + val bodyRanges: BodyRangeList? = message.bodyRanges.filter { it.mentionAci == null }.toList().toBodyRangeList() val mediaMessage = IncomingMediaMessage( from = senderRecipient.id, - sentTimeMillis = envelope.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = System.currentTimeMillis(), parentStoryId = parentStoryId, expiresIn = expiresInMillis.inWholeMilliseconds, @@ -746,7 +761,7 @@ object DataMessageProcessor { body = message.body, groupId = groupId, quote = quoteModel, - mentions = getMentions(message.bodyRangesList), + mentions = getMentions(message.bodyRanges), serverGuid = envelope.serverGuid, messageRanges = bodyRanges ) @@ -769,7 +784,7 @@ object DataMessageProcessor { null } } else { - warn(envelope.timestamp, "Failed to insert story reply.") + warn(envelope.timestamp!!, "Failed to insert story reply.") null } } catch (e: MmsException) { @@ -789,29 +804,30 @@ object DataMessageProcessor { threadRecipientId: RecipientId, receivedTime: Long ): MessageId? { - log(message.timestamp, "Gift message.") + log(message.timestamp!!, "Gift message.") - check(message.giftBadge.hasReceiptCredentialPresentation()) + val giftBadge: DataMessage.GiftBadge = message.giftBadge!! + check(giftBadge.receiptCredentialPresentation != null) notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipientId, metadata.sourceDeviceId) - val token = ReceiptCredentialPresentation(message.giftBadge.receiptCredentialPresentation.toByteArray()).serialize() - val giftBadge = GiftBadge.newBuilder() - .setRedemptionToken(ByteString.copyFrom(token)) - .setRedemptionState(GiftBadge.RedemptionState.PENDING) + val token = ReceiptCredentialPresentation(giftBadge.receiptCredentialPresentation!!.toByteArray()).serialize() + val dbGiftBadge = GiftBadge.Builder() + .redemptionToken(token.toByteString()) + .redemptionState(GiftBadge.RedemptionState.PENDING) .build() val insertResult: InsertResult? = try { val mediaMessage = IncomingMediaMessage( from = senderRecipient.id, - sentTimeMillis = envelope.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, - expiresIn = message.expireTimer.seconds.inWholeMilliseconds, + expiresIn = message.expireTimerDuration.inWholeMilliseconds, isUnidentified = metadata.sealedSender, - body = Base64.encodeBytes(giftBadge.toByteArray()), + body = Base64.encodeBytes(dbGiftBadge.encode()), serverGuid = envelope.serverGuid, - giftBadge = giftBadge + giftBadge = dbGiftBadge ) SignalDatabase.messages.insertSecureDecryptedMessageInbox(mediaMessage, -1).orNull() @@ -840,7 +856,7 @@ object DataMessageProcessor { receivedTime: Long, localMetrics: SignalLocalMetrics.MessageReceive? ): MessageId? { - log(envelope.timestamp, "Media message.") + log(envelope.timestamp!!, "Media message.") notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId) @@ -848,25 +864,25 @@ object DataMessageProcessor { SignalDatabase.messages.beginTransaction() try { - val quote: QuoteModel? = getValidatedQuote(context, envelope.timestamp, message) + val quote: QuoteModel? = getValidatedQuote(context, envelope.timestamp!!, message) val contacts: List = getContacts(message) - val linkPreviews: List = getLinkPreviews(message.previewList, message.body ?: "", false) - val mentions: List = getMentions(message.bodyRangesList.take(BODY_RANGE_PROCESSING_LIMIT)) - val sticker: Attachment? = getStickerAttachment(envelope.timestamp, message) - val attachments: List = message.attachmentsList.toPointersWithinLimit() - val messageRanges: BodyRangeList? = if (message.bodyRangesCount > 0) message.bodyRangesList.asSequence().take(BODY_RANGE_PROCESSING_LIMIT).filter { it.hasStyle() }.toList().toBodyRangeList() else null + val linkPreviews: List = getLinkPreviews(message.preview, message.body ?: "", false) + val mentions: List = getMentions(message.bodyRanges.take(BODY_RANGE_PROCESSING_LIMIT)) + val sticker: Attachment? = getStickerAttachment(envelope.timestamp!!, message) + val attachments: List = message.attachments.toPointersWithinLimit() + val messageRanges: BodyRangeList? = if (message.bodyRanges.isNotEmpty()) message.bodyRanges.asSequence().take(BODY_RANGE_PROCESSING_LIMIT).filter { it.mentionAci == null }.toList().toBodyRangeList() else null - handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimer.seconds, receivedTime) + handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimerDuration, receivedTime) val mediaMessage = IncomingMediaMessage( from = senderRecipient.id, - sentTimeMillis = envelope.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = receivedTime, - expiresIn = message.expireTimer.seconds.inWholeMilliseconds, - isViewOnce = message.isViewOnce, + expiresIn = message.expireTimerDuration.inWholeMilliseconds, + isViewOnce = message.isViewOnce == true, isUnidentified = metadata.sealedSender, - body = message.body.ifEmpty { null }, + body = message.body?.ifEmpty { null }, groupId = groupId, attachments = attachments + if (sticker != null) listOf(sticker) else emptyList(), quote = quote, @@ -909,7 +925,7 @@ object DataMessageProcessor { ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.threadId)) TrimThreadJob.enqueueAsync(insertResult.threadId) - if (message.isViewOnce) { + if (message.isViewOnce == true) { ApplicationDependencies.getViewOnceMessageManager().scheduleIfNecessary() } } @@ -932,23 +948,23 @@ object DataMessageProcessor { receivedTime: Long, localMetrics: SignalLocalMetrics.MessageReceive? ): MessageId? { - log(envelope.timestamp, "Text message.") + log(envelope.timestamp!!, "Text message.") - val body = if (message.hasBody()) message.body else "" + val body = message.body ?: "" - handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimer.seconds, receivedTime) + handlePossibleExpirationUpdate(envelope, metadata, senderRecipient.id, threadRecipient, groupId, message.expireTimerDuration, receivedTime) notifyTypingStoppedFromIncomingMessage(context, senderRecipient, threadRecipient.id, metadata.sourceDeviceId) val textMessage = IncomingTextMessage( senderRecipient.id, metadata.sourceDeviceId, - envelope.timestamp, - envelope.serverTimestamp, + envelope.timestamp!!, + envelope.serverTimestamp!!, receivedTime, body, Optional.ofNullable(groupId), - message.expireTimer.seconds.inWholeMilliseconds, + message.expireTimerDuration.inWholeMilliseconds, metadata.sealedSender, envelope.serverGuid ) @@ -970,10 +986,12 @@ object DataMessageProcessor { senderRecipientId: RecipientId, groupId: GroupId.V2? ) { - log(envelope.timestamp, "Group call update message.") + log(envelope.timestamp!!, "Group call update message.") - if (groupId == null || !message.hasGroupCallUpdate()) { - warn(envelope.timestamp, "Invalid group for group call update message") + val groupCallUpdate: DataMessage.GroupCallUpdate = message.groupCallUpdate!! + + if (groupId == null) { + warn(envelope.timestamp!!, "Invalid group for group call update message") return } @@ -982,8 +1000,8 @@ object DataMessageProcessor { SignalDatabase.calls.insertOrUpdateGroupCallFromExternalEvent( groupRecipientId, senderRecipientId, - envelope.serverTimestamp, - if (message.groupCallUpdate.hasEraId()) message.groupCallUpdate.eraId else null + envelope.serverTimestamp!!, + groupCallUpdate.eraId ) GroupCallPeekJob.enqueue(groupRecipientId) @@ -1000,13 +1018,13 @@ object DataMessageProcessor { fun getMentions(mentionBodyRanges: List): List { return mentionBodyRanges - .filter { it.hasMentionAci() } + .filter { it.mentionAci != null && it.start != null && it.length != null } .mapNotNull { val aci = ACI.parseOrNull(it.mentionAci) if (aci != null && !aci.isUnknown) { val id = Recipient.externalPush(aci).id - Mention(id, it.start, it.length) + Mention(id, it.start!!, it.length!!) } else { null } @@ -1030,19 +1048,15 @@ object DataMessageProcessor { } fun getValidatedQuote(context: Context, timestamp: Long, message: DataMessage): QuoteModel? { - if (!message.hasQuote()) { - return null - } + val quote: DataMessage.Quote = message.quote ?: return null - val quote: DataMessage.Quote = message.quote - - if (quote.id <= 0) { + if (quote.id == null) { warn(timestamp, "Received quote without an ID! Ignoring...") return null } - val authorId = Recipient.externalPush(ServiceId.parseOrThrow(quote.authorAci)).id - var quotedMessage = SignalDatabase.messages.getMessageFor(quote.id, authorId) as? MediaMmsMessageRecord + val authorId = Recipient.externalPush(ServiceId.parseOrThrow(quote.authorAci!!)).id + var quotedMessage = SignalDatabase.messages.getMessageFor(quote.id!!, authorId) as? MediaMmsMessageRecord if (quotedMessage != null && !quotedMessage.isRemoteDelete) { log(timestamp, "Found matching message record...") @@ -1074,7 +1088,7 @@ object DataMessageProcessor { val body = if (quotedMessage.isPaymentNotification) quotedMessage.getDisplayBody(context).toString() else quotedMessage.body return QuoteModel( - quote.id, + quote.id!!, authorId, body, false, @@ -1089,19 +1103,19 @@ object DataMessageProcessor { warn(timestamp, "Didn't find matching message record...") return QuoteModel( - quote.id, + quote.id!!, authorId, - quote.text, + quote.text ?: "", true, - quote.attachmentsList.mapNotNull { PointerAttachment.forPointer(it).orNull() }, - getMentions(quote.bodyRangesList), + quote.attachments.mapNotNull { PointerAttachment.forPointer(it).orNull() }, + getMentions(quote.bodyRanges), QuoteModel.Type.fromProto(quote.type), - quote.bodyRangesList.filterNot { it.hasMentionAci() }.toBodyRangeList() + quote.bodyRanges.filter { it.mentionAci == null }.toBodyRangeList() ) } fun getContacts(message: DataMessage): List { - return message.contactList.map { ContactModelMapper.remoteToLocal(it) } + return message.contact.map { ContactModelMapper.remoteToLocal(it) } } fun getLinkPreviews(previews: List, body: String, isStoryEmbed: Boolean): List { @@ -1113,7 +1127,7 @@ object DataMessageProcessor { return previews .mapNotNull { preview -> - val thumbnail: Attachment? = preview.image.toPointer() + val thumbnail: Attachment? = preview.image?.toPointer() val url: Optional = preview.url.toOptional() val title: Optional = preview.title.toOptional() val description: Optional = preview.description.toOptional() @@ -1122,34 +1136,31 @@ object DataMessageProcessor { val validDomain = url.isPresent && LinkUtil.isValidPreviewUrl(url.get()) val isForCallLink = url.isPresent && CallLinks.isCallLink(url.get()) - if ((hasTitle || isForCallLink) && (presentInBody || isStoryEmbed) && validDomain) { - val linkPreview = LinkPreview(url.get(), title.orElse(""), description.orElse(""), preview.date, thumbnail.toOptional()) + if ((hasTitle || isForCallLink) && (presentInBody || isStoryEmbed) && validDomain && preview.date != null) { + val linkPreview = LinkPreview(url.get(), title.orElse(""), description.orElse(""), preview.date!!, thumbnail.toOptional()) linkPreview } else { - warn(String.format("Discarding an invalid link preview. hasTitle: %b presentInBody: %b isStoryEmbed: %b validDomain: %b", hasTitle, presentInBody, isStoryEmbed, validDomain)) + warn(String.format("Discarding an invalid link preview. hasTitle: %b presentInBody: %b isStoryEmbed: %b validDomain: %b date: %b", hasTitle, presentInBody, isStoryEmbed, validDomain, preview.date != null)) null } } } fun getStickerAttachment(timestamp: Long, message: DataMessage): Attachment? { - if (!message.hasSticker()) { - return null - } + val sticker = message.sticker ?: return null - val sticker = message.sticker - if (!(message.sticker.hasPackId() && message.sticker.hasPackKey() && message.sticker.hasStickerId() && message.sticker.hasData())) { + if (sticker.packId == null || sticker.packKey == null || sticker.stickerId == null || sticker.data_ == null) { warn(timestamp, "Malformed sticker!") return null } - val packId = Hex.toStringCondensed(sticker.packId.toByteArray()) - val packKey = Hex.toStringCondensed(sticker.packKey.toByteArray()) - val stickerId = sticker.stickerId - val emoji = sticker.emoji - val stickerLocator = StickerLocator(packId, packKey, stickerId, emoji) + val packId: String = Hex.toStringCondensed(sticker.packId!!.toByteArray()) + val packKey: String = Hex.toStringCondensed(sticker.packKey!!.toByteArray()) + val stickerId: Int = sticker.stickerId!! + val emoji: String? = sticker.emoji - val stickerRecord = SignalDatabase.stickers.getSticker(stickerLocator.packId, stickerLocator.stickerId, false) + val stickerLocator = StickerLocator(packId, packKey, stickerId, emoji) + val stickerRecord: StickerRecord? = SignalDatabase.stickers.getSticker(stickerLocator.packId, stickerLocator.stickerId, false) return if (stickerRecord != null) { UriAttachment( @@ -1172,7 +1183,7 @@ object DataMessageProcessor { null ) } else { - sticker.data.toPointer(stickerLocator) + sticker.data_!!.toPointer(stickerLocator) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt index c9898a134a..856c8974fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/EditMessageProcessor.kt @@ -32,9 +32,9 @@ import org.thoughtcrime.securesms.util.MessageConstraintsUtil import org.thoughtcrime.securesms.util.hasAudio import org.thoughtcrime.securesms.util.hasSharedContact import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.Envelope import java.util.Optional object EditMessageProcessor { @@ -43,45 +43,45 @@ object EditMessageProcessor { senderRecipient: Recipient, threadRecipient: Recipient, envelope: Envelope, - content: SignalServiceProtos.Content, + content: Content, metadata: EnvelopeMetadata, earlyMessageCacheEntry: EarlyMessageCacheEntry? ) { - val editMessage = content.editMessage + val editMessage = content.editMessage!! - log(envelope.timestamp, "[handleEditMessage] Edit message for " + editMessage.targetSentTimestamp) + log(envelope.timestamp!!, "[handleEditMessage] Edit message for " + editMessage.targetSentTimestamp) - var targetMessage: MediaMmsMessageRecord? = SignalDatabase.messages.getMessageFor(editMessage.targetSentTimestamp, senderRecipient.id) as? MediaMmsMessageRecord + var targetMessage: MediaMmsMessageRecord? = SignalDatabase.messages.getMessageFor(editMessage.targetSentTimestamp!!, senderRecipient.id) as? MediaMmsMessageRecord val targetThreadRecipient: Recipient? = if (targetMessage != null) SignalDatabase.threads.getRecipientForThreadId(targetMessage.threadId) else null if (targetMessage == null || targetThreadRecipient == null) { - warn(envelope.timestamp, "[handleEditMessage] Could not find matching message! timestamp: ${editMessage.targetSentTimestamp} author: ${senderRecipient.id}") + warn(envelope.timestamp!!, "[handleEditMessage] Could not find matching message! timestamp: ${editMessage.targetSentTimestamp} author: ${senderRecipient.id}") if (earlyMessageCacheEntry != null) { - ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.id, editMessage.targetSentTimestamp, earlyMessageCacheEntry) + ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.id, editMessage.targetSentTimestamp!!, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() } return } - val message = editMessage.dataMessage + val message = editMessage.dataMessage!! val isMediaMessage = message.isMediaMessage - val groupId: GroupId.V2? = message.groupV2.groupId + val groupId: GroupId.V2? = message.groupV2?.groupId val originalMessage = targetMessage.originalMessageId?.let { SignalDatabase.messages.getMessageRecord(it.id) } ?: targetMessage - val validTiming = MessageConstraintsUtil.isValidEditMessageReceive(originalMessage, senderRecipient, envelope.serverTimestamp) + val validTiming = MessageConstraintsUtil.isValidEditMessageReceive(originalMessage, senderRecipient, envelope.serverTimestamp!!) val validAuthor = senderRecipient.id == originalMessage.fromRecipient.id val validGroup = groupId == targetThreadRecipient.groupId.orNull() val validTarget = !originalMessage.isViewOnce && !originalMessage.hasAudio() && !originalMessage.hasSharedContact() if (!validTiming || !validAuthor || !validGroup || !validTarget) { - warn(envelope.timestamp, "[handleEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${originalMessage.serverTimestamp}, editAuthor: ${senderRecipient.id}, targetAuthor: ${originalMessage.fromRecipient.id}, editThread: ${threadRecipient.id}, targetThread: ${targetThreadRecipient.id}, validity: (timing: $validTiming, author: $validAuthor, group: $validGroup, target: $validTarget)") + warn(envelope.timestamp!!, "[handleEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${originalMessage.serverTimestamp}, editAuthor: ${senderRecipient.id}, targetAuthor: ${originalMessage.fromRecipient.id}, editThread: ${threadRecipient.id}, targetThread: ${targetThreadRecipient.id}, validity: (timing: $validTiming, author: $validAuthor, group: $validGroup, target: $validTarget)") return } - if (groupId != null && MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp, content, metadata, groupId, message.groupV2, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { - warn(envelope.timestamp, "[handleEditMessage] Group processor indicated we should ignore this.") + if (groupId != null && MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp!!, content, metadata, groupId, message.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { + warn(envelope.timestamp!!, "[handleEditMessage] Group processor indicated we should ignore this.") return } @@ -97,7 +97,7 @@ object EditMessageProcessor { if (insertResult != null) { SignalExecutors.BOUNDED.execute { - ApplicationDependencies.getJobManager().add(SendDeliveryReceiptJob(senderRecipient.id, message.timestamp, MessageId(insertResult.messageId))) + ApplicationDependencies.getJobManager().add(SendDeliveryReceiptJob(senderRecipient.id, message.timestamp!!, MessageId(insertResult.messageId))) } if (targetMessage.expireStarted > 0) { @@ -122,9 +122,9 @@ object EditMessageProcessor { message: DataMessage, targetMessage: MediaMmsMessageRecord ): InsertResult? { - val messageRanges: BodyRangeList? = message.bodyRangesList.filter { it.hasStyle() }.toList().toBodyRangeList() + val messageRanges: BodyRangeList? = message.bodyRanges.filter { it.mentionAci == null }.toList().toBodyRangeList() val targetQuote = targetMessage.quote - val quote: QuoteModel? = if (targetQuote != null && message.hasQuote()) { + val quote: QuoteModel? = if (targetQuote != null && message.quote != null) { QuoteModel( targetQuote.id, targetQuote.author, @@ -138,25 +138,25 @@ object EditMessageProcessor { } else { null } - val attachments = message.attachmentsList.toPointersWithinLimit() + val attachments = message.attachments.toPointersWithinLimit() attachments.filter { MediaUtil.SlideType.LONG_TEXT == MediaUtil.getSlideTypeFromContentType(it.contentType) } val mediaMessage = IncomingMediaMessage( from = senderRecipientId, - sentTimeMillis = message.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = message.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = targetMessage.dateReceived, expiresIn = targetMessage.expiresIn, - isViewOnce = message.isViewOnce, + isViewOnce = message.isViewOnce == true, isUnidentified = metadata.sealedSender, body = message.body, groupId = groupId, attachments = attachments, quote = quote, sharedContacts = emptyList(), - linkPreviews = DataMessageProcessor.getLinkPreviews(message.previewList, message.body ?: "", false), - mentions = DataMessageProcessor.getMentions(message.bodyRangesList), + linkPreviews = DataMessageProcessor.getLinkPreviews(message.preview, message.body ?: "", false), + mentions = DataMessageProcessor.getMentions(message.bodyRanges), serverGuid = envelope.serverGuid, messageRanges = messageRanges, isPushMessage = true @@ -185,8 +185,8 @@ object EditMessageProcessor { var textMessage = IncomingTextMessage( senderRecipientId, metadata.sourceDeviceId, - envelope.timestamp, - envelope.timestamp, + envelope.timestamp!!, + envelope.timestamp!!, targetMessage.dateReceived, message.body, Optional.ofNullable(groupId), diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt index 004e3ff5af..93a407d37f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt @@ -34,7 +34,7 @@ import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.util.UuidUtil import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.Envelope import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit @@ -264,17 +264,17 @@ class IncomingMessageObserver(private val context: Application) { } @VisibleForTesting - fun processEnvelope(bufferedProtocolStore: BufferedProtocolStore, envelope: SignalServiceProtos.Envelope, serverDeliveredTimestamp: Long): List? { - return when (envelope.type.number) { - SignalServiceProtos.Envelope.Type.RECEIPT_VALUE -> { + fun processEnvelope(bufferedProtocolStore: BufferedProtocolStore, envelope: Envelope, serverDeliveredTimestamp: Long): List? { + return when (envelope.type) { + Envelope.Type.RECEIPT -> { processReceipt(envelope) null } - SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE, - SignalServiceProtos.Envelope.Type.CIPHERTEXT_VALUE, - SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER_VALUE, - SignalServiceProtos.Envelope.Type.PLAINTEXT_CONTENT_VALUE -> { + Envelope.Type.PREKEY_BUNDLE, + Envelope.Type.CIPHERTEXT, + Envelope.Type.UNIDENTIFIED_SENDER, + Envelope.Type.PLAINTEXT_CONTENT -> { processMessage(bufferedProtocolStore, envelope, serverDeliveredTimestamp) } @@ -285,12 +285,12 @@ class IncomingMessageObserver(private val context: Application) { } } - private fun processMessage(bufferedProtocolStore: BufferedProtocolStore, envelope: SignalServiceProtos.Envelope, serverDeliveredTimestamp: Long): List { + private fun processMessage(bufferedProtocolStore: BufferedProtocolStore, envelope: Envelope, serverDeliveredTimestamp: Long): List { val localReceiveMetric = SignalLocalMetrics.MessageReceive.start() val result = MessageDecryptor.decrypt(context, bufferedProtocolStore, envelope, serverDeliveredTimestamp) localReceiveMetric.onEnvelopeDecrypted() - SignalLocalMetrics.MessageLatency.onMessageReceived(envelope.serverTimestamp, serverDeliveredTimestamp, envelope.urgent) + SignalLocalMetrics.MessageLatency.onMessageReceived(envelope.serverTimestamp!!, serverDeliveredTimestamp, envelope.urgent!!) when (result) { is MessageDecryptor.Result.Success -> { val job = PushProcessMessageJob.processOrDefer(messageContentProcessor, result, localReceiveMetric) @@ -303,7 +303,7 @@ class IncomingMessageObserver(private val context: Application) { PushProcessMessageErrorJob( result.toMessageState(), result.errorMetadata.toExceptionMetadata(), - result.envelope.timestamp + result.envelope.timestamp!! ) } } @@ -318,17 +318,17 @@ class IncomingMessageObserver(private val context: Application) { return result.followUpOperations } - private fun processReceipt(envelope: SignalServiceProtos.Envelope) { + private fun processReceipt(envelope: Envelope) { if (!UuidUtil.isUuid(envelope.sourceServiceId)) { Log.w(TAG, "Invalid envelope source UUID!") return } - val senderId = RecipientId.from(ServiceId.parseOrThrow(envelope.sourceServiceId)) + val senderId = RecipientId.from(ServiceId.parseOrThrow(envelope.sourceServiceId!!)) Log.i(TAG, "Received server receipt. Sender: $senderId, Device: ${envelope.sourceDevice}, Timestamp: ${envelope.timestamp}") - SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.timestamp, senderId, System.currentTimeMillis()) - SignalDatabase.messageLog.deleteEntryForRecipient(envelope.timestamp, senderId, envelope.sourceDevice) + SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.timestamp!!, senderId, System.currentTimeMillis()) + SignalDatabase.messageLog.deleteEntryForRecipient(envelope.timestamp!!, senderId, envelope.sourceDevice!!) } private fun MessageDecryptor.Result.toMessageState(): MessageState { diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt index a656f3fd1b..a98510b403 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.kt @@ -51,10 +51,11 @@ import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.TypingMessage +import org.whispersystems.signalservice.internal.push.CallMessage +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.GroupContextV2 +import org.whispersystems.signalservice.internal.push.TypingMessage import java.io.IOException import java.util.Optional @@ -123,18 +124,18 @@ open class MessageContentProcessor(private val context: Context) { @Throws(BadGroupIdException::class) private fun getMessageDestination(content: Content, sender: Recipient): Recipient { - return if (content.hasStoryMessage() && content.storyMessage.group.isValid) { - getGroupRecipient(content.storyMessage.group, sender) + return if (content.storyMessage != null && content.storyMessage!!.group.isValid) { + getGroupRecipient(content.storyMessage!!.group, sender) } else if (content.dataMessage.hasGroupContext) { - getGroupRecipient(content.dataMessage.groupV2, sender) - } else if (content.editMessage.dataMessage.hasGroupContext) { - getGroupRecipient(content.editMessage.dataMessage.groupV2, sender) + getGroupRecipient(content.dataMessage!!.groupV2, sender) + } else if (content.editMessage?.dataMessage.hasGroupContext) { + getGroupRecipient(content.editMessage!!.dataMessage!!.groupV2, sender) } else { sender } } - private fun getGroupRecipient(groupContextV2: SignalServiceProtos.GroupContextV2?, senderRecipient: Recipient): Recipient { + private fun getGroupRecipient(groupContextV2: GroupContextV2?, senderRecipient: Recipient): Recipient { return if (groupContextV2 != null) { Recipient.externalPossiblyMigratedGroup(GroupId.v2(groupContextV2.groupMasterKey)) } else { @@ -144,8 +145,8 @@ open class MessageContentProcessor(private val context: Context) { @Throws(BadGroupIdException::class) private fun shouldIgnore(content: Content, senderRecipient: Recipient, threadRecipient: Recipient): Boolean { - if (content.hasDataMessage()) { - val message = content.dataMessage + if (content.dataMessage != null) { + val message = content.dataMessage!! return if (threadRecipient.isGroup && threadRecipient.isBlocked) { true } else if (threadRecipient.isGroup) { @@ -153,7 +154,7 @@ open class MessageContentProcessor(private val context: Context) { return senderRecipient.isBlocked } - val isTextMessage = message.hasBody() + val isTextMessage = message.body != null val isMediaMessage = message.isMediaMessage val isExpireMessage = message.isExpirationUpdate val isGv2Update = message.hasSignedGroupChange @@ -164,15 +165,15 @@ open class MessageContentProcessor(private val context: Context) { } else { senderRecipient.isBlocked } - } else if (content.hasCallMessage()) { + } else if (content.callMessage != null) { return senderRecipient.isBlocked - } else if (content.hasTypingMessage()) { + } else if (content.typingMessage != null) { if (senderRecipient.isBlocked) { return true } - if (content.typingMessage.hasGroupId()) { - val groupId: GroupId = GroupId.push(content.typingMessage.groupId) + if (content.typingMessage!!.groupId != null) { + val groupId: GroupId = GroupId.push(content.typingMessage!!.groupId!!) val groupRecipient = Recipient.externalPossiblyMigratedGroup(groupId) return if (groupRecipient.isBlocked || !groupRecipient.isActiveGroup) { true @@ -181,7 +182,7 @@ open class MessageContentProcessor(private val context: Context) { groupRecord.isPresent && groupRecord.get().isAnnouncementGroup && !groupRecord.get().admins.contains(senderRecipient) } } - } else if (content.hasStoryMessage()) { + } else if (content.storyMessage != null) { return if (threadRecipient.isGroup && threadRecipient.isBlocked) { true } else { @@ -227,7 +228,7 @@ open class MessageContentProcessor(private val context: Context) { content: Content, metadata: EnvelopeMetadata, groupId: GroupId.V2, - groupV2: SignalServiceProtos.GroupContextV2, + groupV2: GroupContextV2, senderRecipient: Recipient, groupSecretParams: GroupSecretParams? = null ): Gv2PreProcessResult { @@ -254,12 +255,12 @@ open class MessageContentProcessor(private val context: Context) { } if (groupRecord.isPresent && groupRecord.get().isAnnouncementGroup && !groupRecord.get().admins.contains(senderRecipient)) { - if (content.hasDataMessage()) { - if (content.dataMessage.hasDisallowedAnnouncementOnlyContent) { + if (content.dataMessage != null) { + if (content.dataMessage!!.hasDisallowedAnnouncementOnlyContent) { Log.w(TAG, "Ignoring message from ${senderRecipient.id} because it has disallowed content, and they're not an admin in an announcement-only group.") return Gv2PreProcessResult.IGNORE } - } else if (content.hasTypingMessage()) { + } else if (content.typingMessage != null) { Log.w(TAG, "Ignoring typing indicator from ${senderRecipient.id} because they're not an admin in an announcement-only group.") return Gv2PreProcessResult.IGNORE } @@ -275,14 +276,19 @@ open class MessageContentProcessor(private val context: Context) { fun updateGv2GroupFromServerOrP2PChange( context: Context, timestamp: Long, - groupV2: SignalServiceProtos.GroupContextV2, + groupV2: GroupContextV2, localRecord: Optional, groupSecretParams: GroupSecretParams? = null ): GroupsV2StateProcessor.GroupUpdateResult? { return try { val signedGroupChange: ByteArray? = if (groupV2.hasSignedGroupChange) groupV2.signedGroupChange else null val updatedTimestamp = if (signedGroupChange != null) timestamp else timestamp - 1 - GroupManager.updateGroupFromServer(context, groupV2.groupMasterKey, localRecord, groupSecretParams, groupV2.revision, updatedTimestamp, signedGroupChange) + if (groupV2.revision != null) { + GroupManager.updateGroupFromServer(context, groupV2.groupMasterKey, localRecord, groupSecretParams, groupV2.revision!!, updatedTimestamp, signedGroupChange) + } else { + warn(timestamp, "Ignore group update message without a revision") + null + } } catch (e: GroupNotAMemberException) { warn(timestamp, "Ignoring message for a group we're not in") null @@ -331,11 +337,11 @@ open class MessageContentProcessor(private val context: Context) { val earlyCacheEntries: List? = ApplicationDependencies .getEarlyMessageCache() - .retrieve(senderRecipient.id, envelope.timestamp) + .retrieve(senderRecipient.id, envelope.timestamp!!) .orNull() if (!processingEarlyContent && earlyCacheEntries != null) { - log(envelope.timestamp, "Found " + earlyCacheEntries.size + " dependent item(s) that were retrieved earlier. Processing.") + log(envelope.timestamp!!, "Found " + earlyCacheEntries.size + " dependent item(s) that were retrieved earlier. Processing.") for (entry in earlyCacheEntries) { handleMessage(senderRecipient, entry.envelope, entry.content, entry.metadata, entry.serverDeliveredTimestamp, processingEarlyContent = true, localMetric = null) } @@ -411,17 +417,17 @@ open class MessageContentProcessor(private val context: Context) { val threadRecipient = getMessageDestination(content, senderRecipient) if (shouldIgnore(content, senderRecipient, threadRecipient)) { - log(envelope.timestamp, "Ignoring message.") + log(envelope.timestamp!!, "Ignoring message.") return } - val pending: PendingRetryReceiptModel? = ApplicationDependencies.getPendingRetryReceiptCache().get(senderRecipient.id, envelope.timestamp) - val receivedTime: Long = handlePendingRetry(pending, envelope.timestamp, threadRecipient) + val pending: PendingRetryReceiptModel? = ApplicationDependencies.getPendingRetryReceiptCache().get(senderRecipient.id, envelope.timestamp!!) + val receivedTime: Long = handlePendingRetry(pending, envelope.timestamp!!, threadRecipient) - log(envelope.timestamp, "Beginning message processing. Sender: " + formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId)) + log(envelope.timestamp!!, "Beginning message processing. Sender: " + formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId)) localMetric?.onPreProcessComplete() when { - content.hasDataMessage() -> { + content.dataMessage != null -> { DataMessageProcessor.process( context, senderRecipient, @@ -435,7 +441,7 @@ open class MessageContentProcessor(private val context: Context) { ) } - content.hasSyncMessage() -> { + content.syncMessage != null -> { TextSecurePreferences.setMultiDevice(context, true) SyncMessageProcessor.process( @@ -448,21 +454,20 @@ open class MessageContentProcessor(private val context: Context) { ) } - content.hasCallMessage() -> { - log(envelope.timestamp, "Got call message...") + content.callMessage != null -> { + log(envelope.timestamp!!, "Got call message...") - val message: SignalServiceProtos.CallMessage = content.callMessage - val destinationDeviceId: Int? = if (message.hasDestinationDeviceId()) message.destinationDeviceId else null + val message: CallMessage = content.callMessage!! - if (destinationDeviceId != null && destinationDeviceId != SignalStore.account().deviceId) { - log(envelope.timestamp, "Ignoring call message that is not for this device! intended: $destinationDeviceId, this: ${SignalStore.account().deviceId}") + if (message.destinationDeviceId != null && message.destinationDeviceId != SignalStore.account().deviceId) { + log(envelope.timestamp!!, "Ignoring call message that is not for this device! intended: ${message.destinationDeviceId}, this: ${SignalStore.account().deviceId}") return } CallMessageProcessor.process(senderRecipient, envelope, content, metadata, serverDeliveredTimestamp) } - content.hasReceiptMessage() -> { + content.receiptMessage != null -> { ReceiptMessageProcessor.process( context, senderRecipient, @@ -473,11 +478,11 @@ open class MessageContentProcessor(private val context: Context) { ) } - content.hasTypingMessage() -> { - handleTypingMessage(envelope, metadata, content.typingMessage, senderRecipient) + content.typingMessage != null -> { + handleTypingMessage(envelope, metadata, content.typingMessage!!, senderRecipient) } - content.hasStoryMessage() -> { + content.storyMessage != null -> { StoryMessageProcessor.process( envelope, content, @@ -487,11 +492,11 @@ open class MessageContentProcessor(private val context: Context) { ) } - content.hasDecryptionErrorMessage() -> { + content.decryptionErrorMessage != null -> { handleRetryReceipt(envelope, metadata, content.decryptionErrorMessage!!.toDecryptionErrorMessage(metadata), senderRecipient) } - content.hasEditMessage() -> { + content.editMessage != null -> { EditMessageProcessor.process( context, senderRecipient, @@ -503,17 +508,17 @@ open class MessageContentProcessor(private val context: Context) { ) } - content.hasSenderKeyDistributionMessage() || content.hasPniSignatureMessage() -> { + content.senderKeyDistributionMessage != null || content.pniSignatureMessage != null -> { // Already handled, here in order to prevent unrecognized message log } else -> { - warn(envelope.timestamp, "Got unrecognized message!") + warn(envelope.timestamp!!, "Got unrecognized message!") } } if (pending != null) { - warn(envelope.timestamp, "Pending retry was processed. Deleting.") + warn(envelope.timestamp!!, "Pending retry was processed. Deleting.") ApplicationDependencies.getPendingRetryReceiptCache().delete(pending) } } @@ -529,10 +534,10 @@ open class MessageContentProcessor(private val context: Context) { return } - val threadId: Long = if (typingMessage.hasGroupId()) { - val groupId = GroupId.push(typingMessage.groupId) + val threadId: Long = if (typingMessage.groupId != null) { + val groupId = GroupId.push(typingMessage.groupId!!) if (!SignalDatabase.groups.isCurrentMember(groupId, senderRecipient.id)) { - warn(envelope.timestamp, "Seen typing indicator for non-member " + senderRecipient.id) + warn(envelope.timestamp!!, "Seen typing indicator for non-member " + senderRecipient.id) return } @@ -543,7 +548,7 @@ open class MessageContentProcessor(private val context: Context) { } if (threadId <= 0) { - warn(envelope.timestamp, "Couldn't find a matching thread for a typing message.") + warn(envelope.timestamp!!, "Couldn't find a matching thread for a typing message.") return } @@ -558,19 +563,19 @@ open class MessageContentProcessor(private val context: Context) { private fun handleRetryReceipt(envelope: Envelope, metadata: EnvelopeMetadata, decryptionErrorMessage: DecryptionErrorMessage, senderRecipient: Recipient) { if (!FeatureFlags.retryReceipts()) { - warn(envelope.timestamp, "[RetryReceipt] Feature flag disabled, skipping retry receipt.") + warn(envelope.timestamp!!, "[RetryReceipt] Feature flag disabled, skipping retry receipt.") return } if (decryptionErrorMessage.deviceId != SignalStore.account().deviceId) { - log(envelope.timestamp, "[RetryReceipt] Received a DecryptionErrorMessage targeting a linked device. Ignoring.") + log(envelope.timestamp!!, "[RetryReceipt] Received a DecryptionErrorMessage targeting a linked device. Ignoring.") return } val sentTimestamp = decryptionErrorMessage.timestamp - warn(envelope.timestamp, "[RetryReceipt] Received a retry receipt from ${formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId)} for message with timestamp $sentTimestamp.") + warn(envelope.timestamp!!, "[RetryReceipt] Received a retry receipt from ${formatSender(senderRecipient.id, metadata.sourceServiceId, metadata.sourceDeviceId)} for message with timestamp $sentTimestamp.") if (!senderRecipient.hasServiceId()) { - warn(envelope.timestamp, "[RetryReceipt] Requester ${senderRecipient.id} somehow has no UUID! timestamp: $sentTimestamp") + warn(envelope.timestamp!!, "[RetryReceipt] Requester ${senderRecipient.id} somehow has no UUID! timestamp: $sentTimestamp") return } @@ -593,18 +598,18 @@ open class MessageContentProcessor(private val context: Context) { val relatedMessage = findRetryReceiptRelatedMessage(messageLogEntry, sentTimestamp) if (relatedMessage == null) { - warn(envelope.timestamp, "[RetryReceipt-SK] The related message could not be found! There shouldn't be any sender key resends where we can't find the related message. Skipping.") + warn(envelope.timestamp!!, "[RetryReceipt-SK] The related message could not be found! There shouldn't be any sender key resends where we can't find the related message. Skipping.") return } val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(relatedMessage.threadId) if (threadRecipient == null) { - warn(envelope.timestamp, "[RetryReceipt-SK] Could not find a thread recipient! Skipping.") + warn(envelope.timestamp!!, "[RetryReceipt-SK] Could not find a thread recipient! Skipping.") return } if (!threadRecipient.isPushV2Group && !threadRecipient.isDistributionList) { - warn(envelope.timestamp, "[RetryReceipt-SK] Thread recipient is not a V2 group or distribution list! Skipping.") + warn(envelope.timestamp!!, "[RetryReceipt-SK] Thread recipient is not a V2 group or distribution list! Skipping.") return } @@ -628,7 +633,7 @@ open class MessageContentProcessor(private val context: Context) { SignalDatabase.senderKeyShared.delete(distributionId, setOf(requesterAddress)) if (messageLogEntry != null) { - warn(envelope.timestamp, "[RetryReceipt-SK] Found MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp. Scheduling a resend.") + warn(envelope.timestamp!!, "[RetryReceipt-SK] Found MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp. Scheduling a resend.") ApplicationDependencies.getJobManager().add( ResendMessageJob( messageLogEntry.recipientId, @@ -641,7 +646,7 @@ open class MessageContentProcessor(private val context: Context) { ) ) } else { - warn(envelope.timestamp, "[RetryReceipt-SK] Unable to find MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp for ${if (groupId != null) "group $groupId" else "distribution list"}. Scheduling a job to send them the SenderKeyDistributionMessage. Membership will be checked there.") + warn(envelope.timestamp!!, "[RetryReceipt-SK] Unable to find MSL entry for ${requester.id} ($requesterAddress) with timestamp $sentTimestamp for ${if (groupId != null) "group $groupId" else "distribution list"}. Scheduling a job to send them the SenderKeyDistributionMessage. Membership will be checked there.") ApplicationDependencies.getJobManager().add(SenderKeyDistributionSendJob(requester.id, threadRecipient.id)) } } @@ -653,13 +658,13 @@ open class MessageContentProcessor(private val context: Context) { if (decryptionErrorMessage.ratchetKey.isPresent && ratchetKeyMatches(requester, metadata.sourceDeviceId, decryptionErrorMessage.ratchetKey.get()) ) { - warn(envelope.timestamp, "[RetryReceipt-I] Ratchet key matches. Archiving the session.") + warn(envelope.timestamp!!, "[RetryReceipt-I] Ratchet key matches. Archiving the session.") ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.requireServiceId(), metadata.sourceDeviceId) archivedSession = true } if (messageLogEntry != null) { - warn(envelope.timestamp, "[RetryReceipt-I] Found an entry in the MSL. Resending.") + warn(envelope.timestamp!!, "[RetryReceipt-I] Found an entry in the MSL. Resending.") ApplicationDependencies.getJobManager().add( ResendMessageJob( messageLogEntry.recipientId, @@ -672,10 +677,10 @@ open class MessageContentProcessor(private val context: Context) { ) ) } else if (archivedSession) { - warn(envelope.timestamp, "[RetryReceipt-I] Could not find an entry in the MSL, but we archived the session, so we're sending a null message to complete the reset.") + warn(envelope.timestamp!!, "[RetryReceipt-I] Could not find an entry in the MSL, but we archived the session, so we're sending a null message to complete the reset.") ApplicationDependencies.getJobManager().add(NullMessageSendJob(requester.id)) } else { - warn(envelope.timestamp, "[RetryReceipt-I] Could not find an entry in the MSL. Skipping.") + warn(envelope.timestamp!!, "[RetryReceipt-I] Could not find an entry in the MSL. Skipping.") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt index 15069646b8..baed1183f9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt @@ -60,9 +60,9 @@ 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.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.PniSignatureMessage +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.PniSignatureMessage import java.util.Optional import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.DurationUnit @@ -103,7 +103,7 @@ object MessageDecryptor { return Result.Ignore(envelope, serverDeliveredTimestamp, emptyList()) } - if (destination == selfPni && envelope.hasSourceServiceId()) { + if (destination == selfPni && envelope.sourceServiceId != null) { Log.i(TAG, "${logPrefix(envelope)} Received a message at our PNI. Marking as needing a PNI signature.") val sourceServiceId = ServiceId.parseOrNull(envelope.sourceServiceId) @@ -116,7 +116,7 @@ object MessageDecryptor { } } - if (destination == selfPni && !envelope.hasSourceServiceId()) { + if (destination == selfPni && envelope.sourceServiceId == null) { Log.w(TAG, "${logPrefix(envelope)} Got a sealed sender message to our PNI? Invalid message, ignoring.") return Result.Ignore(envelope, serverDeliveredTimestamp, emptyList()) } @@ -143,7 +143,7 @@ object MessageDecryptor { return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList()) } - Log.d(TAG, "${logPrefix(envelope, cipherResult)} Successfully decrypted the envelope in ${(endTimeNanos - startTimeNanos).nanoseconds.toDouble(DurationUnit.MILLISECONDS).roundedString(2)} ms (GUID ${envelope.serverGuid}). Delivery latency: ${serverDeliveredTimestamp - envelope.serverTimestamp} ms, Urgent: ${envelope.urgent}") + Log.d(TAG, "${logPrefix(envelope, cipherResult)} Successfully decrypted the envelope in ${(endTimeNanos - startTimeNanos).nanoseconds.toDouble(DurationUnit.MILLISECONDS).roundedString(2)} ms (GUID ${envelope.serverGuid}). Delivery latency: ${serverDeliveredTimestamp - envelope.serverTimestamp!!} ms, Urgent: ${envelope.urgent}") val validationResult: EnvelopeContentValidator.Result = EnvelopeContentValidator.validate(envelope, cipherResult.content) @@ -163,17 +163,17 @@ object MessageDecryptor { } // Must handle SKDM's immediately, because subsequent decryptions could rely on it - if (cipherResult.content.hasSenderKeyDistributionMessage()) { + if (cipherResult.content.senderKeyDistributionMessage != null) { handleSenderKeyDistributionMessage( envelope, cipherResult.metadata.sourceServiceId, cipherResult.metadata.sourceDeviceId, - SenderKeyDistributionMessage(cipherResult.content.senderKeyDistributionMessage.toByteArray()), + SenderKeyDistributionMessage(cipherResult.content.senderKeyDistributionMessage!!.toByteArray()), bufferedProtocolStore.getAciStore() ) } - if (cipherResult.content.hasPniSignatureMessage()) { + if (cipherResult.content.pniSignatureMessage != null) { if (cipherResult.metadata.sourceServiceId is ACI) { handlePniSignatureMessage( envelope, @@ -181,19 +181,19 @@ object MessageDecryptor { cipherResult.metadata.sourceServiceId as ACI, cipherResult.metadata.sourceE164, cipherResult.metadata.sourceDeviceId, - cipherResult.content.pniSignatureMessage + cipherResult.content.pniSignatureMessage!! ) } else { Log.w(TAG, "${logPrefix(envelope)} Ignoring PNI signature because the sourceServiceId isn't an ACI!") } - } else if (cipherResult.content.hasPniSignatureMessage()) { + } else if (cipherResult.content.pniSignatureMessage != null) { Log.w(TAG, "${logPrefix(envelope)} Ignoring PNI signature because the feature flag is disabled!") } // TODO We can move this to the "message processing" stage once we give it access to the envelope. But for now it'll stay here. - if (envelope.hasReportingToken() && envelope.reportingToken != null && envelope.reportingToken.size() > 0) { + if (envelope.reportingToken != null && envelope.reportingToken!!.size > 0) { val sender = RecipientId.from(cipherResult.metadata.sourceServiceId) - SignalDatabase.recipients.setReportingToken(sender, envelope.reportingToken.toByteArray()) + SignalDatabase.recipients.setReportingToken(sender, envelope.reportingToken!!.toByteArray()) } Result.Success(envelope, serverDeliveredTimestamp, cipherResult.content, cipherResult.metadata, followUpOperations.toUnmodifiableList()) @@ -218,7 +218,7 @@ object MessageDecryptor { followUpOperations += FollowUpOperation { val sender: Recipient = Recipient.external(context, e.sender) - AutomaticSessionResetJob(sender.id, e.senderDevice, envelope.timestamp) + AutomaticSessionResetJob(sender.id, e.senderDevice, envelope.timestamp!!) } Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList()) @@ -281,7 +281,7 @@ object MessageDecryptor { Log.w(TAG, "${logPrefix(envelope)} Decryption error for a sync message! Enqueuing a session reset job.") followUpOperations += FollowUpOperation { - AutomaticSessionResetJob(sender.id, senderDevice, envelope.timestamp) + AutomaticSessionResetJob(sender.id, senderDevice, envelope.timestamp!!) } return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations) @@ -309,7 +309,7 @@ object MessageDecryptor { SignalDatabase.threads.getOrCreateThreadIdFor(sender) } - ApplicationDependencies.getPendingRetryReceiptCache().insert(sender.id, senderDevice, envelope.timestamp, receivedTimestamp, threadId) + ApplicationDependencies.getPendingRetryReceiptCache().insert(sender.id, senderDevice, envelope.timestamp!!, receivedTimestamp, threadId) ApplicationDependencies.getPendingRetryReceiptManager().scheduleIfNecessary() null } @@ -334,7 +334,7 @@ object MessageDecryptor { private fun handlePniSignatureMessage(envelope: Envelope, protocolStore: BufferedProtocolStore, aci: ACI, e164: String?, deviceId: Int, pniSignatureMessage: PniSignatureMessage) { Log.i(TAG, "${logPrefix(envelope, aci)} Processing PniSignatureMessage") - val pni: PNI = PNI.parseOrThrow(pniSignatureMessage.pni.toByteArray()) + val pni: PNI = PNI.parseOrThrow(pniSignatureMessage.pni!!.toByteArray()) if (SignalDatabase.recipients.isAssociated(aci, pni)) { Log.i(TAG, "${logPrefix(envelope, aci)}[handlePniSignatureMessage] ACI ($aci) and PNI ($pni) are already associated.") @@ -356,7 +356,7 @@ object MessageDecryptor { return } - if (pniIdentity.verifyAlternateIdentity(aciIdentity, pniSignatureMessage.signature.toByteArray())) { + if (pniIdentity.verifyAlternateIdentity(aciIdentity, pniSignatureMessage.signature!!.toByteArray())) { Log.i(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] PNI signature is valid. Associating ACI ($aci) with PNI ($pni)") SignalDatabase.recipients.getAndPossiblyMergePnpVerified(aci, pni, e164) } else { @@ -387,28 +387,28 @@ object MessageDecryptor { } private fun logPrefix(envelope: Envelope): String { - return logPrefix(envelope.timestamp, envelope.sourceServiceId ?: "", envelope.sourceDevice) + return logPrefix(envelope.timestamp!!, envelope.sourceServiceId ?: "", envelope.sourceDevice) } private fun logPrefix(envelope: Envelope, sender: ServiceId): String { - return logPrefix(envelope.timestamp, sender.toString(), envelope.sourceDevice) + return logPrefix(envelope.timestamp!!, sender.toString(), envelope.sourceDevice) } private fun logPrefix(envelope: Envelope, cipherResult: SignalServiceCipherResult): String { - return logPrefix(envelope.timestamp, cipherResult.metadata.sourceServiceId.toString(), cipherResult.metadata.sourceDeviceId) + return logPrefix(envelope.timestamp!!, cipherResult.metadata.sourceServiceId.toString(), cipherResult.metadata.sourceDeviceId) } private fun logPrefix(envelope: Envelope, exception: ProtocolException): String { return if (exception.sender != null) { - logPrefix(envelope.timestamp, exception.sender, exception.senderDevice) + logPrefix(envelope.timestamp!!, exception.sender, exception.senderDevice) } else { - logPrefix(envelope.timestamp, envelope.sourceServiceId, envelope.sourceDevice) + logPrefix(envelope.timestamp!!, envelope.sourceServiceId, envelope.sourceDevice) } } - private fun logPrefix(timestamp: Long, sender: String?, deviceId: Int): String { + private fun logPrefix(timestamp: Long, sender: String?, deviceId: Int?): String { val senderString = sender ?: "null" - return "[$timestamp] $senderString:$deviceId |" + return "[$timestamp] $senderString:${deviceId ?: 0} |" } private fun buildSendRetryReceiptJob(envelope: Envelope, protocolException: ProtocolException, sender: Recipient): SendRetryReceiptJob { @@ -419,11 +419,11 @@ object MessageDecryptor { originalContent = protocolException.unidentifiedSenderMessageContent.get().content envelopeType = protocolException.unidentifiedSenderMessageContent.get().type } else { - originalContent = envelope.content.toByteArray() - envelopeType = envelope.type.number.toCiphertextMessageType() + originalContent = envelope.content!!.toByteArray() + envelopeType = envelope.type!!.value.toCiphertextMessageType() } - val decryptionErrorMessage: DecryptionErrorMessage = DecryptionErrorMessage.forOriginalMessage(originalContent, envelopeType, envelope.timestamp, protocolException.senderDevice) + val decryptionErrorMessage: DecryptionErrorMessage = DecryptionErrorMessage.forOriginalMessage(originalContent, envelopeType, envelope.timestamp!!, protocolException.senderDevice) val groupId: GroupId? = protocolException.parseGroupId(envelope) return SendRetryReceiptJob(sender.id, Optional.ofNullable(groupId), decryptionErrorMessage) } @@ -443,10 +443,10 @@ object MessageDecryptor { private fun Int.toCiphertextMessageType(): Int { return when (this) { - Envelope.Type.CIPHERTEXT_VALUE -> CiphertextMessage.WHISPER_TYPE - Envelope.Type.PREKEY_BUNDLE_VALUE -> CiphertextMessage.PREKEY_TYPE - Envelope.Type.UNIDENTIFIED_SENDER_VALUE -> CiphertextMessage.SENDERKEY_TYPE - Envelope.Type.PLAINTEXT_CONTENT_VALUE -> CiphertextMessage.PLAINTEXT_CONTENT_TYPE + Envelope.Type.CIPHERTEXT.value -> CiphertextMessage.WHISPER_TYPE + Envelope.Type.PREKEY_BUNDLE.value -> CiphertextMessage.PREKEY_TYPE + Envelope.Type.UNIDENTIFIED_SENDER.value -> CiphertextMessage.SENDERKEY_TYPE + Envelope.Type.PLAINTEXT_CONTENT.value -> CiphertextMessage.PLAINTEXT_CONTENT_TYPE else -> CiphertextMessage.WHISPER_TYPE } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt index a4b916c8e3..ffcf9e941e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt @@ -13,19 +13,19 @@ import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.EarlyMessageCacheEntry import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.ReceiptMessage +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.ReceiptMessage object ReceiptMessageProcessor { - fun process(context: Context, senderRecipient: Recipient, envelope: Envelope, content: SignalServiceProtos.Content, metadata: EnvelopeMetadata, earlyMessageCacheEntry: EarlyMessageCacheEntry?) { - val receiptMessage = content.receiptMessage + fun process(context: Context, senderRecipient: Recipient, envelope: Envelope, content: Content, metadata: EnvelopeMetadata, earlyMessageCacheEntry: EarlyMessageCacheEntry?) { + val receiptMessage = content.receiptMessage!! when (receiptMessage.type) { ReceiptMessage.Type.DELIVERY -> handleDeliveryReceipt(envelope, metadata, receiptMessage, senderRecipient.id) ReceiptMessage.Type.READ -> handleReadReceipt(context, senderRecipient.id, envelope, metadata, receiptMessage, earlyMessageCacheEntry) ReceiptMessage.Type.VIEWED -> handleViewedReceipt(context, envelope, metadata, receiptMessage, senderRecipient.id, earlyMessageCacheEntry) - else -> warn(envelope.timestamp, "Unknown recipient message type ${receiptMessage.type}") + else -> warn(envelope.timestamp!!, "Unknown recipient message type ${receiptMessage.type}") } } @@ -36,12 +36,12 @@ object ReceiptMessageProcessor { deliveryReceipt: ReceiptMessage, senderRecipientId: RecipientId ) { - log(envelope.timestamp, "Processing delivery receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${deliveryReceipt.timestampList.joinToString(", ")}") + log(envelope.timestamp!!, "Processing delivery receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${deliveryReceipt.timestamp.joinToString(", ")}") - val missingTargetTimestamps: Set = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestampList, senderRecipientId, envelope.timestamp) + val missingTargetTimestamps: Set = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestamp, senderRecipientId, envelope.timestamp!!) for (targetTimestamp in missingTargetTimestamps) { - warn(envelope.timestamp, "[handleDeliveryReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId") + warn(envelope.timestamp!!, "[handleDeliveryReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId") // Early delivery receipts are special-cased in the database methods } @@ -49,8 +49,8 @@ object ReceiptMessageProcessor { PushProcessEarlyMessagesJob.enqueue() } - SignalDatabase.pendingPniSignatureMessages.acknowledgeReceipts(senderRecipientId, deliveryReceipt.timestampList, metadata.sourceDeviceId) - SignalDatabase.messageLog.deleteEntriesForRecipient(deliveryReceipt.timestampList, senderRecipientId, metadata.sourceDeviceId) + SignalDatabase.pendingPniSignatureMessages.acknowledgeReceipts(senderRecipientId, deliveryReceipt.timestamp, metadata.sourceDeviceId) + SignalDatabase.messageLog.deleteEntriesForRecipient(deliveryReceipt.timestamp, senderRecipientId, metadata.sourceDeviceId) } @SuppressLint("DefaultLocale") @@ -63,19 +63,19 @@ object ReceiptMessageProcessor { earlyMessageCacheEntry: EarlyMessageCacheEntry? ) { if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { - log(envelope.timestamp, "Ignoring read receipts for IDs: " + readReceipt.timestampList.joinToString(", ")) + log(envelope.timestamp!!, "Ignoring read receipts for IDs: " + readReceipt.timestamp.joinToString(", ")) return } - log(envelope.timestamp, "Processing read receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${readReceipt.timestampList.joinToString(", ")}") + log(envelope.timestamp!!, "Processing read receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${readReceipt.timestamp.joinToString(", ")}") - val missingTargetTimestamps: Set = SignalDatabase.messages.incrementReadReceiptCounts(readReceipt.timestampList, senderRecipientId, envelope.timestamp) + val missingTargetTimestamps: Set = SignalDatabase.messages.incrementReadReceiptCounts(readReceipt.timestamp, senderRecipientId, envelope.timestamp!!) if (missingTargetTimestamps.isNotEmpty()) { val selfId = Recipient.self().id for (targetTimestamp in missingTargetTimestamps) { - warn(envelope.timestamp, "[handleReadReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt, so associating with message from self ($selfId)") + warn(envelope.timestamp!!, "[handleReadReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt, so associating with message from self ($selfId)") if (earlyMessageCacheEntry != null) { ApplicationDependencies.getEarlyMessageCache().store(selfId, targetTimestamp, earlyMessageCacheEntry) } @@ -99,28 +99,28 @@ object ReceiptMessageProcessor { val storyViewedReceipts = SignalStore.storyValues().viewedReceiptsEnabled if (!readReceipts && !storyViewedReceipts) { - log(envelope.timestamp, "Ignoring viewed receipts for IDs: ${viewedReceipt.timestampList.joinToString(", ")}") + log(envelope.timestamp!!, "Ignoring viewed receipts for IDs: ${viewedReceipt.timestamp.joinToString(", ")}") return } - log(envelope.timestamp, "Processing viewed receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Only Stories: ${!readReceipts}, Timestamps: ${viewedReceipt.timestampList.joinToString(", ")}") + log(envelope.timestamp!!, "Processing viewed receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Only Stories: ${!readReceipts}, Timestamps: ${viewedReceipt.timestamp.joinToString(", ")}") val missingTargetTimestamps: Set = if (readReceipts && storyViewedReceipts) { - SignalDatabase.messages.incrementViewedReceiptCounts(viewedReceipt.timestampList, senderRecipientId, envelope.timestamp) + SignalDatabase.messages.incrementViewedReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) } else if (readReceipts) { - SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(viewedReceipt.timestampList, senderRecipientId, envelope.timestamp) + SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) } else { - SignalDatabase.messages.incrementViewedStoryReceiptCounts(viewedReceipt.timestampList, senderRecipientId, envelope.timestamp) + SignalDatabase.messages.incrementViewedStoryReceiptCounts(viewedReceipt.timestamp, senderRecipientId, envelope.timestamp!!) } - val foundTargetTimestamps: Set = viewedReceipt.timestampList.toSet() - missingTargetTimestamps.toSet() + val foundTargetTimestamps: Set = viewedReceipt.timestamp.toSet() - missingTargetTimestamps.toSet() SignalDatabase.messages.updateViewedStories(foundTargetTimestamps) if (missingTargetTimestamps.isNotEmpty()) { val selfId = Recipient.self().id for (targetTimestamp in missingTargetTimestamps) { - warn(envelope.timestamp, "[handleViewedReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt so associating with message from self ($selfId)") + warn(envelope.timestamp!!, "[handleViewedReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt so associating with message from self ($selfId)") if (earlyMessageCacheEntry != null) { ApplicationDependencies.getEarlyMessageCache().store(selfId, targetTimestamp, earlyMessageCacheEntry) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/SignalServiceProtoUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/SignalServiceProtoUtil.kt index b868a2496c..33e14aee61 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/SignalServiceProtoUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/SignalServiceProtoUtil.kt @@ -1,7 +1,8 @@ package org.thoughtcrime.securesms.messages -import com.google.protobuf.ByteString -import com.google.protobuf.GeneratedMessageLite +import ProtoUtil.isNotEmpty +import com.squareup.wire.Message +import okio.ByteString import org.signal.core.util.orNull import org.signal.libsignal.protocol.message.DecryptionErrorMessage import org.signal.libsignal.zkgroup.groups.GroupMasterKey @@ -18,79 +19,78 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin import org.whispersystems.signalservice.api.payments.Money import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.util.AttachmentPointerUtil -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage.Payment -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2 -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.StoryMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.Sent -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.TypingMessage +import org.whispersystems.signalservice.internal.push.AttachmentPointer +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.DataMessage.Payment +import org.whispersystems.signalservice.internal.push.GroupContextV2 +import org.whispersystems.signalservice.internal.push.StoryMessage +import org.whispersystems.signalservice.internal.push.SyncMessage.Sent +import org.whispersystems.signalservice.internal.push.TypingMessage import java.util.Optional - -private val ByteString.isNotEmpty: Boolean - get() = !this.isEmpty +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds object SignalServiceProtoUtil { /** Contains some user data that affects the conversation */ val DataMessage.hasRenderableContent: Boolean get() { - return attachmentsList.isNotEmpty() || - hasBody() || - hasQuote() || - contactList.isNotEmpty() || - previewList.isNotEmpty() || - bodyRangesList.isNotEmpty() || - hasSticker() || - hasReaction() || + return attachments.isNotEmpty() || + body != null || + quote != null || + contact.isNotEmpty() || + preview.isNotEmpty() || + bodyRanges.isNotEmpty() || + sticker != null || + reaction != null || hasRemoteDelete } val DataMessage.hasDisallowedAnnouncementOnlyContent: Boolean get() { - return hasBody() || - attachmentsList.isNotEmpty() || - hasQuote() || - previewList.isNotEmpty() || - bodyRangesList.isNotEmpty() || - hasSticker() + return body != null || + attachments.isNotEmpty() || + quote != null || + preview.isNotEmpty() || + bodyRanges.isNotEmpty() || + sticker != null } val DataMessage.isExpirationUpdate: Boolean - get() = flags and DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE != 0 + get() = flags != null && flags!! and DataMessage.Flags.EXPIRATION_TIMER_UPDATE.value != 0 val DataMessage.hasRemoteDelete: Boolean - get() = hasDelete() && delete.hasTargetSentTimestamp() + get() = delete != null && delete!!.targetSentTimestamp != null val DataMessage.isGroupV2Update: Boolean get() = !hasRenderableContent && hasSignedGroupChange - val DataMessage.hasGroupContext: Boolean - get() = hasGroupV2() && groupV2.hasMasterKey() && groupV2.masterKey.isNotEmpty + val DataMessage?.hasGroupContext: Boolean + get() = this?.groupV2?.masterKey.isNotEmpty() val DataMessage.hasSignedGroupChange: Boolean - get() = hasGroupContext && groupV2.hasSignedGroupChange + get() = hasGroupContext && groupV2!!.hasSignedGroupChange val DataMessage.isMediaMessage: Boolean - get() = attachmentsList.isNotEmpty() || hasQuote() || contactList.isNotEmpty() || hasSticker() || bodyRangesList.isNotEmpty() || previewList.isNotEmpty() + get() = attachments.isNotEmpty() || quote != null || contact.isNotEmpty() || sticker != null || bodyRanges.isNotEmpty() || preview.isNotEmpty() val DataMessage.isEndSession: Boolean - get() = flags and DataMessage.Flags.END_SESSION_VALUE != 0 + get() = flags != null && flags!! and DataMessage.Flags.END_SESSION.value != 0 val DataMessage.isStoryReaction: Boolean - get() = hasReaction() && hasStoryContext() + get() = reaction != null && storyContext != null val DataMessage.isPaymentActivationRequest: Boolean - get() = hasPayment() && payment.hasActivation() && payment.activation.type == Payment.Activation.Type.REQUEST + get() = payment?.activation?.type == Payment.Activation.Type.REQUEST val DataMessage.isPaymentActivated: Boolean - get() = hasPayment() && payment.hasActivation() && payment.activation.type == Payment.Activation.Type.ACTIVATED + get() = payment?.activation?.type == Payment.Activation.Type.ACTIVATED val DataMessage.isInvalid: Boolean get() { - if (isViewOnce) { - val contentType = attachmentsList[0].contentType.lowercase() - return attachmentsList.size != 1 || !MediaUtil.isImageOrVideoType(contentType) + if (isViewOnce == true) { + val contentType = attachments[0].contentType?.lowercase() + return attachments.size != 1 || !MediaUtil.isImageOrVideoType(contentType) } return false } @@ -98,31 +98,34 @@ object SignalServiceProtoUtil { val DataMessage.isEmptyGroupV2Message: Boolean get() = hasGroupContext && !isGroupV2Update && !hasRenderableContent + val DataMessage.expireTimerDuration: Duration + get() = (expireTimer ?: 0).seconds + val GroupContextV2.hasSignedGroupChange: Boolean - get() = hasGroupChange() && groupChange.isNotEmpty + get() = groupChange.isNotEmpty() val GroupContextV2.signedGroupChange: ByteArray - get() = groupChange.toByteArray() + get() = groupChange!!.toByteArray() val GroupContextV2.groupMasterKey: GroupMasterKey - get() = GroupMasterKey(masterKey.toByteArray()) + get() = GroupMasterKey(masterKey!!.toByteArray()) val GroupContextV2?.isValid: Boolean - get() = this != null && masterKey.isNotEmpty + get() = this?.masterKey.isNotEmpty() val GroupContextV2.groupId: GroupId.V2? get() = if (isValid) GroupId.v2(groupMasterKey) else null val StoryMessage.type: StoryType get() { - return if (allowsReplies) { - if (hasTextAttachment()) { + return if (allowsReplies == true) { + if (textAttachment != null) { StoryType.TEXT_STORY_WITH_REPLIES } else { StoryType.STORY_WITH_REPLIES } } else { - if (hasTextAttachment()) { + if (textAttachment != null) { StoryType.TEXT_STORY_WITHOUT_REPLIES } else { StoryType.STORY_WITHOUT_REPLIES @@ -131,16 +134,16 @@ object SignalServiceProtoUtil { } fun Sent.isUnidentified(serviceId: ServiceId?): Boolean { - return serviceId != null && unidentifiedStatusList.firstOrNull { ServiceId.parseOrNull(it.destinationServiceId) == serviceId }?.unidentified ?: false + return serviceId != null && unidentifiedStatus.firstOrNull { ServiceId.parseOrNull(it.destinationServiceId) == serviceId }?.unidentified ?: false } val Sent.serviceIdsToUnidentifiedStatus: Map get() { - return unidentifiedStatusList + return unidentifiedStatus .mapNotNull { status -> val serviceId = ServiceId.parseOrNull(status.destinationServiceId) if (serviceId != null) { - serviceId to status.unidentified + serviceId to (status.unidentified ?: false) } else { null } @@ -149,7 +152,7 @@ object SignalServiceProtoUtil { } val TypingMessage.hasStarted: Boolean - get() = hasAction() && action == TypingMessage.Action.STARTED + get() = action == TypingMessage.Action.STARTED fun ByteString.toDecryptionErrorMessage(metadata: EnvelopeMetadata): DecryptionErrorMessage { try { @@ -180,7 +183,7 @@ object SignalServiceProtoUtil { } @Suppress("UNCHECKED_CAST") - inline fun , BuilderType : GeneratedMessageLite.Builder> GeneratedMessageLite.Builder.buildWith(block: BuilderType.() -> Unit): MessageType { + inline fun , BuilderType : Message.Builder> Message.Builder.buildWith(block: BuilderType.() -> Unit): MessageType { block(this as BuilderType) return build() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt index 128705f7e7..98a1c4df3b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/StoryMessageProcessor.kt @@ -20,28 +20,30 @@ import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.FeatureFlags import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.StoryMessage +import org.whispersystems.signalservice.internal.push.TextAttachment object StoryMessageProcessor { - fun process(envelope: Envelope, content: SignalServiceProtos.Content, metadata: EnvelopeMetadata, senderRecipient: Recipient, threadRecipient: Recipient) { - val storyMessage = content.storyMessage + fun process(envelope: Envelope, content: Content, metadata: EnvelopeMetadata, senderRecipient: Recipient, threadRecipient: Recipient) { + val storyMessage = content.storyMessage!! - log(envelope.timestamp, "Story message.") + log(envelope.timestamp!!, "Story message.") if (threadRecipient.isInactiveGroup) { - warn(envelope.timestamp, "Dropping a group story from a group we're no longer in.") + warn(envelope.timestamp!!, "Dropping a group story from a group we're no longer in.") return } if (threadRecipient.isGroup && !SignalDatabase.groups.isCurrentMember(threadRecipient.requireGroupId().requirePush(), senderRecipient.id)) { - warn(envelope.timestamp, "Dropping a group story from a user who's no longer a member.") + warn(envelope.timestamp!!, "Dropping a group story from a user who's no longer a member.") return } if (!threadRecipient.isGroup && !(senderRecipient.isProfileSharing || senderRecipient.isSystemContact)) { - warn(envelope.timestamp, "Dropping story from an untrusted source.") + warn(envelope.timestamp!!, "Dropping story from an untrusted source.") return } @@ -50,29 +52,29 @@ object StoryMessageProcessor { SignalDatabase.messages.beginTransaction() try { - val storyType: StoryType = if (storyMessage.hasAllowsReplies() && storyMessage.allowsReplies) { - StoryType.withReplies(storyMessage.hasTextAttachment()) + val storyType: StoryType = if (storyMessage.allowsReplies == true) { + StoryType.withReplies(isTextStory = storyMessage.textAttachment != null) } else { - StoryType.withoutReplies(storyMessage.hasTextAttachment()) + StoryType.withoutReplies(isTextStory = storyMessage.textAttachment != null) } val mediaMessage = IncomingMediaMessage( from = senderRecipient.id, - sentTimeMillis = envelope.timestamp, - serverTimeMillis = envelope.serverTimestamp, + sentTimeMillis = envelope.timestamp!!, + serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = System.currentTimeMillis(), storyType = storyType, isUnidentified = metadata.sealedSender, body = serializeTextAttachment(storyMessage), - groupId = storyMessage.group.groupId, - attachments = if (storyMessage.hasFileAttachment()) listOfNotNull(storyMessage.fileAttachment.toPointer()) else emptyList(), + groupId = storyMessage.group?.groupId, + attachments = listOfNotNull(storyMessage.fileAttachment?.toPointer()), linkPreviews = DataMessageProcessor.getLinkPreviews( - previews = if (storyMessage.textAttachment.hasPreview()) listOf(storyMessage.textAttachment.preview) else emptyList(), + previews = listOfNotNull(storyMessage.textAttachment?.preview), body = "", isStoryEmbed = true ), serverGuid = envelope.serverGuid, - messageRanges = storyMessage.bodyRangesList.filterNot { it.hasMentionAci() }.toBodyRangeList() + messageRanges = storyMessage.bodyRanges.filter { it.mentionAci == null }.toBodyRangeList() ) insertResult = SignalDatabase.messages.insertSecureDecryptedMessageInbox(mediaMessage, -1).orNull() @@ -91,66 +93,60 @@ object StoryMessageProcessor { } } - fun serializeTextAttachment(story: SignalServiceProtos.StoryMessage): String? { - if (!story.hasTextAttachment()) { - return null - } - val textAttachment = story.textAttachment - val builder = StoryTextPost.newBuilder() + fun serializeTextAttachment(story: StoryMessage): String? { + val textAttachment = story.textAttachment ?: return null + val builder = StoryTextPost.Builder() - if (textAttachment.hasText()) { - builder.body = textAttachment.text + if (textAttachment.text != null) { + builder.body = textAttachment.text!! } - if (textAttachment.hasTextStyle()) { - when (textAttachment.textStyle) { - SignalServiceProtos.TextAttachment.Style.DEFAULT -> builder.style = StoryTextPost.Style.DEFAULT - SignalServiceProtos.TextAttachment.Style.REGULAR -> builder.style = StoryTextPost.Style.REGULAR - SignalServiceProtos.TextAttachment.Style.BOLD -> builder.style = StoryTextPost.Style.BOLD - SignalServiceProtos.TextAttachment.Style.SERIF -> builder.style = StoryTextPost.Style.SERIF - SignalServiceProtos.TextAttachment.Style.SCRIPT -> builder.style = StoryTextPost.Style.SCRIPT - SignalServiceProtos.TextAttachment.Style.CONDENSED -> builder.style = StoryTextPost.Style.CONDENSED - else -> Unit - } + when (textAttachment.textStyle) { + TextAttachment.Style.DEFAULT -> builder.style = StoryTextPost.Style.DEFAULT + TextAttachment.Style.REGULAR -> builder.style = StoryTextPost.Style.REGULAR + TextAttachment.Style.BOLD -> builder.style = StoryTextPost.Style.BOLD + TextAttachment.Style.SERIF -> builder.style = StoryTextPost.Style.SERIF + TextAttachment.Style.SCRIPT -> builder.style = StoryTextPost.Style.SCRIPT + TextAttachment.Style.CONDENSED -> builder.style = StoryTextPost.Style.CONDENSED + null -> Unit } - if (textAttachment.hasTextBackgroundColor()) { - builder.textBackgroundColor = textAttachment.textBackgroundColor + if (textAttachment.textBackgroundColor != null) { + builder.textBackgroundColor = textAttachment.textBackgroundColor!! } - if (textAttachment.hasTextForegroundColor()) { - builder.textForegroundColor = textAttachment.textForegroundColor + if (textAttachment.textForegroundColor != null) { + builder.textForegroundColor = textAttachment.textForegroundColor!! } - val chatColorBuilder = ChatColor.newBuilder() + val chatColorBuilder = ChatColor.Builder() - if (textAttachment.hasColor()) { - chatColorBuilder.setSingleColor(ChatColor.SingleColor.newBuilder().setColor(textAttachment.color)) - } else if (textAttachment.hasGradient()) { - val gradient = textAttachment.gradient - val linearGradientBuilder = ChatColor.LinearGradient.newBuilder() - linearGradientBuilder.rotation = gradient.angle.toFloat() + if (textAttachment.color != null) { + chatColorBuilder.singleColor(ChatColor.SingleColor.Builder().color(textAttachment.color!!).build()) + } else if (textAttachment.gradient != null) { + val gradient = textAttachment.gradient!! + val linearGradientBuilder = ChatColor.LinearGradient.Builder() + linearGradientBuilder.rotation = (gradient.angle ?: 0).toFloat() - if (gradient.positionsList.size > 1 && gradient.colorsList.size == gradient.positionsList.size) { - val positions = ArrayList(gradient.positionsList) + if (gradient.positions.size > 1 && gradient.colors.size == gradient.positions.size) { + val positions = ArrayList(gradient.positions) positions[0] = 0f positions[positions.size - 1] = 1f - linearGradientBuilder.addAllColors(ArrayList(gradient.colorsList)) - linearGradientBuilder.addAllPositions(positions) - } else if (gradient.colorsList.isNotEmpty()) { + linearGradientBuilder.colors(ArrayList(gradient.colors)) + linearGradientBuilder.positions(positions) + } else if (gradient.colors.isNotEmpty()) { warn("Incoming text story has color / position mismatch. Defaulting to start and end colors.") - linearGradientBuilder.addColors(gradient.colorsList[0]) - linearGradientBuilder.addColors(gradient.colorsList[gradient.colorsList.size - 1]) - linearGradientBuilder.addAllPositions(listOf(0f, 1f)) + linearGradientBuilder.colors(listOf(gradient.colors[0], gradient.colors[gradient.colors.size - 1])) + linearGradientBuilder.positions(listOf(0f, 1f)) } else { warn("Incoming text story did not have a valid linear gradient.") - linearGradientBuilder.addAllColors(listOf(Color.BLACK, Color.BLACK)) - linearGradientBuilder.addAllPositions(listOf(0f, 1f)) + linearGradientBuilder.colors(listOf(Color.BLACK, Color.BLACK)) + linearGradientBuilder.positions(listOf(0f, 1f)) } - chatColorBuilder.setLinearGradient(linearGradientBuilder) + chatColorBuilder.linearGradient(linearGradientBuilder.build()) } - builder.setBackground(chatColorBuilder) + builder.background(chatColorBuilder.build()) - return Base64.encodeBytes(builder.build().toByteArray()) + return Base64.encodeBytes(builder.build().encode()) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/StorySendUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/StorySendUtil.kt index 2cbef95479..c168e6dfce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/StorySendUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/StorySendUtil.kt @@ -1,26 +1,26 @@ package org.thoughtcrime.securesms.messages -import com.google.protobuf.InvalidProtocolBufferException import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost import org.thoughtcrime.securesms.mms.OutgoingMessage import org.thoughtcrime.securesms.util.Base64 import org.whispersystems.signalservice.api.messages.SignalServicePreview import org.whispersystems.signalservice.api.messages.SignalServiceTextAttachment +import java.io.IOException import java.util.Optional import kotlin.math.roundToInt object StorySendUtil { @JvmStatic - @Throws(InvalidProtocolBufferException::class) + @Throws(IOException::class) fun deserializeBodyToStoryTextAttachment(message: OutgoingMessage, getPreviewsFor: (OutgoingMessage) -> List): SignalServiceTextAttachment { - val storyTextPost = StoryTextPost.parseFrom(Base64.decode(message.body)) + val storyTextPost = StoryTextPost.ADAPTER.decode(Base64.decode(message.body)) val preview = if (message.linkPreviews.isEmpty()) { Optional.empty() } else { Optional.of(getPreviewsFor(message)[0]) } - return if (storyTextPost.background.hasLinearGradient()) { + return if (storyTextPost.background!!.linearGradient != null) { SignalServiceTextAttachment.forGradientBackground( Optional.ofNullable(storyTextPost.body), Optional.ofNullable(getStyle(storyTextPost.style)), @@ -28,9 +28,9 @@ object StorySendUtil { Optional.of(storyTextPost.textBackgroundColor), preview, SignalServiceTextAttachment.Gradient( - Optional.of(storyTextPost.background.linearGradient.rotation.roundToInt()), - ArrayList(storyTextPost.background.linearGradient.colorsList), - ArrayList(storyTextPost.background.linearGradient.positionsList) + Optional.of(storyTextPost.background.linearGradient!!.rotation.roundToInt()), + ArrayList(storyTextPost.background.linearGradient.colors), + ArrayList(storyTextPost.background.linearGradient.positions) ) ) } else { @@ -40,7 +40,7 @@ object StorySendUtil { Optional.of(storyTextPost.textForegroundColor), Optional.of(storyTextPost.textBackgroundColor), preview, - storyTextPost.background.singleColor.color + storyTextPost.background.singleColor!!.color ) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt index ab1c9649d7..601fe69382 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt @@ -1,8 +1,9 @@ package org.thoughtcrime.securesms.messages +import ProtoUtil.isNotEmpty import android.content.Context -import com.google.protobuf.ByteString import com.mobilecoin.lib.exceptions.SerializationException +import okio.ByteString import org.signal.core.util.Hex import org.signal.core.util.orNull import org.signal.libsignal.protocol.util.Pair @@ -54,6 +55,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.linkpreview.LinkPreview import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.log import org.thoughtcrime.securesms.messages.MessageContentProcessor.Companion.warn +import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.expireTimerDuration import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.groupId import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.groupMasterKey import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.hasGroupContext @@ -100,27 +102,28 @@ import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.storage.StorageKey -import org.whispersystems.signalservice.internal.push.SignalServiceProtos -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.StoryMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.Blocked -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallLinkUpdate -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallLogEvent -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.Configuration -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.FetchLatest -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.MessageRequestResponse -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.Read -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.Request -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.Sent -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.StickerPackOperation -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.ViewOnceOpen +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.EditMessage +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.StoryMessage +import org.whispersystems.signalservice.internal.push.SyncMessage +import org.whispersystems.signalservice.internal.push.SyncMessage.Blocked +import org.whispersystems.signalservice.internal.push.SyncMessage.CallLinkUpdate +import org.whispersystems.signalservice.internal.push.SyncMessage.CallLogEvent +import org.whispersystems.signalservice.internal.push.SyncMessage.Configuration +import org.whispersystems.signalservice.internal.push.SyncMessage.FetchLatest +import org.whispersystems.signalservice.internal.push.SyncMessage.MessageRequestResponse +import org.whispersystems.signalservice.internal.push.SyncMessage.Read +import org.whispersystems.signalservice.internal.push.SyncMessage.Request +import org.whispersystems.signalservice.internal.push.SyncMessage.Sent +import org.whispersystems.signalservice.internal.push.SyncMessage.StickerPackOperation +import org.whispersystems.signalservice.internal.push.SyncMessage.ViewOnceOpen +import org.whispersystems.signalservice.internal.push.Verified import java.io.IOException import java.util.Optional import java.util.UUID -import kotlin.time.Duration.Companion.seconds +import kotlin.time.Duration object SyncMessageProcessor { @@ -132,27 +135,27 @@ object SyncMessageProcessor { metadata: EnvelopeMetadata, earlyMessageCacheEntry: EarlyMessageCacheEntry? ) { - val syncMessage = content.syncMessage + val syncMessage = content.syncMessage!! when { - syncMessage.hasSent() -> handleSynchronizeSentMessage(context, envelope, content, metadata, syncMessage.sent, senderRecipient, earlyMessageCacheEntry) - syncMessage.hasRequest() -> handleSynchronizeRequestMessage(context, syncMessage.request, envelope.timestamp) - syncMessage.readList.isNotEmpty() -> handleSynchronizeReadMessage(context, syncMessage.readList, envelope.timestamp, earlyMessageCacheEntry) - syncMessage.viewedList.isNotEmpty() -> handleSynchronizeViewedMessage(context, syncMessage.viewedList, envelope.timestamp) - syncMessage.hasViewOnceOpen() -> handleSynchronizeViewOnceOpenMessage(context, syncMessage.viewOnceOpen, envelope.timestamp, earlyMessageCacheEntry) - syncMessage.hasVerified() -> handleSynchronizeVerifiedMessage(context, syncMessage.verified) - syncMessage.stickerPackOperationList.isNotEmpty() -> handleSynchronizeStickerPackOperation(syncMessage.stickerPackOperationList, envelope.timestamp) - syncMessage.hasConfiguration() -> handleSynchronizeConfigurationMessage(context, syncMessage.configuration, envelope.timestamp) - syncMessage.hasBlocked() -> handleSynchronizeBlockedListMessage(syncMessage.blocked) - syncMessage.hasFetchLatest() && syncMessage.fetchLatest.hasType() -> handleSynchronizeFetchMessage(syncMessage.fetchLatest.type, envelope.timestamp) - syncMessage.hasMessageRequestResponse() -> handleSynchronizeMessageRequestResponse(syncMessage.messageRequestResponse, envelope.timestamp) - syncMessage.hasOutgoingPayment() -> handleSynchronizeOutgoingPayment(syncMessage.outgoingPayment, envelope.timestamp) - syncMessage.hasKeys() && syncMessage.keys.hasStorageService() -> handleSynchronizeKeys(syncMessage.keys.storageService, envelope.timestamp) - syncMessage.hasContacts() -> handleSynchronizeContacts(syncMessage.contacts, envelope.timestamp) - syncMessage.hasCallEvent() -> handleSynchronizeCallEvent(syncMessage.callEvent, envelope.timestamp) - syncMessage.hasCallLinkUpdate() -> handleSynchronizeCallLink(syncMessage.callLinkUpdate, envelope.timestamp) - syncMessage.hasCallLogEvent() -> handleSynchronizeCallLogEvent(syncMessage.callLogEvent, envelope.timestamp) - else -> warn(envelope.timestamp, "Contains no known sync types...") + syncMessage.sent != null -> handleSynchronizeSentMessage(context, envelope, content, metadata, syncMessage.sent!!, senderRecipient, earlyMessageCacheEntry) + syncMessage.request != null -> handleSynchronizeRequestMessage(context, syncMessage.request!!, envelope.timestamp!!) + syncMessage.read.isNotEmpty() -> handleSynchronizeReadMessage(context, syncMessage.read, envelope.timestamp!!, earlyMessageCacheEntry) + syncMessage.viewed.isNotEmpty() -> handleSynchronizeViewedMessage(context, syncMessage.viewed, envelope.timestamp!!) + syncMessage.viewOnceOpen != null -> handleSynchronizeViewOnceOpenMessage(context, syncMessage.viewOnceOpen!!, envelope.timestamp!!, earlyMessageCacheEntry) + syncMessage.verified != null -> handleSynchronizeVerifiedMessage(context, syncMessage.verified!!) + syncMessage.stickerPackOperation.isNotEmpty() -> handleSynchronizeStickerPackOperation(syncMessage.stickerPackOperation, envelope.timestamp!!) + syncMessage.configuration != null -> handleSynchronizeConfigurationMessage(context, syncMessage.configuration!!, envelope.timestamp!!) + syncMessage.blocked != null -> handleSynchronizeBlockedListMessage(syncMessage.blocked!!) + syncMessage.fetchLatest?.type != null -> handleSynchronizeFetchMessage(syncMessage.fetchLatest!!.type!!, envelope.timestamp!!) + syncMessage.messageRequestResponse != null -> handleSynchronizeMessageRequestResponse(syncMessage.messageRequestResponse!!, envelope.timestamp!!) + syncMessage.outgoingPayment != null -> handleSynchronizeOutgoingPayment(syncMessage.outgoingPayment!!, envelope.timestamp!!) + syncMessage.keys?.storageService != null -> handleSynchronizeKeys(syncMessage.keys!!.storageService!!, envelope.timestamp!!) + syncMessage.contacts != null -> handleSynchronizeContacts(syncMessage.contacts!!, envelope.timestamp!!) + syncMessage.callEvent != null -> handleSynchronizeCallEvent(syncMessage.callEvent!!, envelope.timestamp!!) + syncMessage.callLinkUpdate != null -> handleSynchronizeCallLink(syncMessage.callLinkUpdate!!, envelope.timestamp!!) + syncMessage.callLogEvent != null -> handleSynchronizeCallLogEvent(syncMessage.callLogEvent!!, envelope.timestamp!!) + else -> warn(envelope.timestamp!!, "Contains no known sync types...") } } @@ -166,54 +169,64 @@ object SyncMessageProcessor { senderRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry? ) { - log(envelope.timestamp, "Processing sent transcript for message with ID ${sent.timestamp}") + log(envelope.timestamp!!, "Processing sent transcript for message with ID ${sent.timestamp!!}") try { - if (sent.hasStoryMessage() || sent.storyMessageRecipientsList.isNotEmpty()) { + if (sent.storyMessage != null || sent.storyMessageRecipients.isNotEmpty()) { handleSynchronizeSentStoryMessage(envelope, sent) return } - if (sent.hasEditMessage()) { + if (sent.editMessage != null) { handleSynchronizeSentEditMessage(context, envelope, sent, senderRecipient, earlyMessageCacheEntry) return } - val dataMessage = sent.message - val groupId: GroupId.V2? = if (dataMessage.hasGroupContext) GroupId.v2(dataMessage.groupV2.groupMasterKey) else null + if (sent.isRecipientUpdate == true) { + handleGroupRecipientUpdate(sent, envelope.timestamp!!) + return + } + + val dataMessage = if (sent.message != null) { + sent.message!! + } else { + warn(envelope.timestamp!!, "Sync message missing nested message to sync") + return + } + + val groupId: GroupId.V2? = if (dataMessage.hasGroupContext) GroupId.v2(dataMessage.groupV2!!.groupMasterKey) else null if (groupId != null) { - if (MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp, content, metadata, groupId, dataMessage.groupV2, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { + if (MessageContentProcessor.handleGv2PreProcessing(context, envelope.timestamp!!, content, metadata, groupId, dataMessage.groupV2!!, senderRecipient) == MessageContentProcessor.Gv2PreProcessResult.IGNORE) { return } } var threadId: Long = -1 when { - sent.isRecipientUpdate -> handleGroupRecipientUpdate(sent, envelope.timestamp) - dataMessage.isEndSession -> threadId = handleSynchronizeSentEndSessionMessage(context, sent, envelope.timestamp) + dataMessage.isEndSession -> threadId = handleSynchronizeSentEndSessionMessage(context, sent, envelope.timestamp!!) dataMessage.isGroupV2Update -> { handleSynchronizeSentGv2Update(context, envelope, sent) threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent)) } - dataMessage.hasGroupCallUpdate() -> DataMessageProcessor.handleGroupCallUpdateMessage(envelope, dataMessage, senderRecipient.id, groupId) - dataMessage.isEmptyGroupV2Message -> warn(envelope.timestamp, "Empty GV2 message! Doing nothing.") + dataMessage.groupCallUpdate != null -> DataMessageProcessor.handleGroupCallUpdateMessage(envelope, dataMessage, senderRecipient.id, groupId) + dataMessage.isEmptyGroupV2Message -> warn(envelope.timestamp!!, "Empty GV2 message! Doing nothing.") dataMessage.isExpirationUpdate -> threadId = handleSynchronizeSentExpirationUpdate(sent) - dataMessage.hasStoryContext() -> threadId = handleSynchronizeSentStoryReply(sent, envelope.timestamp) - dataMessage.hasReaction() -> { + dataMessage.storyContext != null -> threadId = handleSynchronizeSentStoryReply(sent, envelope.timestamp!!) + dataMessage.reaction != null -> { DataMessageProcessor.handleReaction(context, envelope, dataMessage, senderRecipient.id, earlyMessageCacheEntry) threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent)) } dataMessage.hasRemoteDelete -> DataMessageProcessor.handleRemoteDelete(context, envelope, dataMessage, senderRecipient.id, earlyMessageCacheEntry) - dataMessage.isMediaMessage -> threadId = handleSynchronizeSentMediaMessage(context, sent, envelope.timestamp) - else -> threadId = handleSynchronizeSentTextMessage(sent, envelope.timestamp) + dataMessage.isMediaMessage -> threadId = handleSynchronizeSentMediaMessage(context, sent, envelope.timestamp!!) + else -> threadId = handleSynchronizeSentTextMessage(sent, envelope.timestamp!!) } if (groupId != null && SignalDatabase.groups.isUnknownGroup(groupId)) { - DataMessageProcessor.handleUnknownGroupMessage(envelope.timestamp, dataMessage.groupV2) + DataMessageProcessor.handleUnknownGroupMessage(envelope.timestamp!!, dataMessage.groupV2!!) } - if (dataMessage.hasProfileKey()) { + if (dataMessage.profileKey.isNotEmpty()) { val recipient: Recipient = getSyncMessageDestination(sent) if (!recipient.isSystemContact && !recipient.isProfileSharing) { SignalDatabase.recipients.setProfileSharing(recipient.id, true) @@ -226,11 +239,11 @@ object SyncMessageProcessor { } if (SignalStore.rateLimit().needsRecaptcha()) { - log(envelope.timestamp, "Got a sent transcript while in reCAPTCHA mode. Assuming we're good to message again.") + log(envelope.timestamp!!, "Got a sent transcript while in reCAPTCHA mode. Assuming we're good to message again.") RateLimitUtil.retryAllRateLimitedMessages(context) } - ApplicationDependencies.getMessageNotifier().setLastDesktopActivityTimestamp(sent.timestamp) + ApplicationDependencies.getMessageNotifier().setLastDesktopActivityTimestamp(sent.timestamp!!) } catch (e: MmsException) { throw StorageFailedException(e, metadata.sourceServiceId.toString(), metadata.sourceDeviceId) } @@ -238,9 +251,9 @@ object SyncMessageProcessor { private fun getSyncMessageDestination(message: Sent): Recipient { return if (message.message.hasGroupContext) { - Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.message.groupV2.groupMasterKey)) + Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.message!!.groupV2!!.groupMasterKey)) } else { - Recipient.externalPush(SignalServiceAddress(ServiceId.parseOrThrow(message.destinationServiceId), message.destinationE164)) + Recipient.externalPush(SignalServiceAddress(ServiceId.parseOrThrow(message.destinationServiceId!!), message.destinationE164)) } } @@ -252,30 +265,32 @@ object SyncMessageProcessor { senderRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry? ) { - val targetSentTimestamp: Long = sent.editMessage.targetSentTimestamp + val editMessage: EditMessage = sent.editMessage!! + val targetSentTimestamp: Long = editMessage.targetSentTimestamp!! val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, senderRecipient.id) val senderRecipientId = senderRecipient.id if (targetMessage == null) { - warn(envelope.timestamp, "[handleSynchronizeSentEditMessage] Could not find matching message! targetTimestamp: $targetSentTimestamp author: $senderRecipientId") + warn(envelope.timestamp!!, "[handleSynchronizeSentEditMessage] Could not find matching message! targetTimestamp: $targetSentTimestamp author: $senderRecipientId") if (earlyMessageCacheEntry != null) { ApplicationDependencies.getEarlyMessageCache().store(senderRecipientId, targetSentTimestamp, earlyMessageCacheEntry) PushProcessEarlyMessagesJob.enqueue() } - } else if (MessageConstraintsUtil.isValidEditMessageReceive(targetMessage, senderRecipient, envelope.serverTimestamp)) { - val message = sent.editMessage.dataMessage + } else if (MessageConstraintsUtil.isValidEditMessageReceive(targetMessage, senderRecipient, envelope.serverTimestamp!!)) { + val message: DataMessage = editMessage.dataMessage!! val toRecipient: Recipient = if (message.hasGroupContext) { - Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.groupV2.groupMasterKey)) + Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.groupV2!!.groupMasterKey)) } else { - Recipient.externalPush(ServiceId.parseOrThrow(sent.destinationServiceId)) + Recipient.externalPush(ServiceId.parseOrThrow(sent.destinationServiceId!!)) } + if (message.isMediaMessage) { - handleSynchronizeSentEditMediaMessage(context, targetMessage, toRecipient, sent, message, envelope.timestamp) + handleSynchronizeSentEditMediaMessage(context, targetMessage, toRecipient, sent, message, envelope.timestamp!!) } else { - handleSynchronizeSentEditTextMessage(targetMessage, toRecipient, sent, message, envelope.timestamp) + handleSynchronizeSentEditTextMessage(targetMessage, toRecipient, sent, message, envelope.timestamp!!) } } else { - warn(envelope.timestamp, "[handleSynchronizeSentEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${targetMessage.serverTimestamp}, sendAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}") + warn(envelope.timestamp!!, "[handleSynchronizeSentEditMessage] Invalid message edit! editTime: ${envelope.serverTimestamp}, targetTime: ${targetMessage.serverTimestamp}, sendAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}") } } @@ -289,7 +304,7 @@ object SyncMessageProcessor { log(envelopeTimestamp, "Synchronize sent edit text message for message: ${targetMessage.id}") val body = message.body ?: "" - val bodyRanges = message.bodyRangesList.filterNot { it.hasMentionAci() }.toBodyRangeList() + val bodyRanges = message.bodyRanges.filter { it.mentionAci == null }.toBodyRangeList() val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(toRecipient) val isGroup = toRecipient.isGroup @@ -299,7 +314,7 @@ object SyncMessageProcessor { val outgoingMessage = OutgoingMessage( recipient = toRecipient, body = body, - timestamp = sent.timestamp, + timestamp = sent.timestamp!!, expiresIn = targetMessage.expiresIn, isSecure = true, bodyRanges = bodyRanges, @@ -311,7 +326,7 @@ object SyncMessageProcessor { } else { val outgoingTextMessage = OutgoingMessage( threadRecipient = toRecipient, - sentTimeMillis = sent.timestamp, + sentTimeMillis = sent.timestamp!!, body = body, expiresIn = targetMessage.expiresIn, isUrgent = true, @@ -330,8 +345,8 @@ object SyncMessageProcessor { } if (toRecipient.isSelf) { - SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, toRecipient.id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, toRecipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp!!, toRecipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp!!, toRecipient.id, System.currentTimeMillis()) } } @@ -347,12 +362,12 @@ object SyncMessageProcessor { val quote: QuoteModel? = DataMessageProcessor.getValidatedQuote(context, envelopeTimestamp, message) val sharedContacts: List = DataMessageProcessor.getContacts(message) - val previews: List = DataMessageProcessor.getLinkPreviews(message.previewList, message.body ?: "", false) - val mentions: List = DataMessageProcessor.getMentions(message.bodyRangesList) - val viewOnce: Boolean = message.isViewOnce - val bodyRanges: BodyRangeList? = message.bodyRangesList.toBodyRangeList() + val previews: List = DataMessageProcessor.getLinkPreviews(message.preview, message.body ?: "", false) + val mentions: List = DataMessageProcessor.getMentions(message.bodyRanges) + val viewOnce: Boolean = message.isViewOnce == true + val bodyRanges: BodyRangeList? = message.bodyRanges.toBodyRangeList() - val syncAttachments = message.attachmentsList.toPointersWithinLimit().filter { + val syncAttachments = message.attachments.toPointersWithinLimit().filter { MediaUtil.SlideType.LONG_TEXT == MediaUtil.getSlideTypeFromContentType(it.contentType) } @@ -363,7 +378,7 @@ object SyncMessageProcessor { recipient = toRecipient, body = message.body ?: "", attachments = syncAttachments.ifEmpty { (targetMessage as? MediaMmsMessageRecord)?.slideDeck?.asAttachments() ?: emptyList() }, - timestamp = sent.timestamp, + timestamp = sent.timestamp!!, expiresIn = targetMessage.expiresIn, viewOnce = viewOnce, quote = quote, @@ -394,8 +409,8 @@ object SyncMessageProcessor { ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, true, targetMessage.expireStarted, targetMessage.expireStarted) } if (toRecipient.isSelf) { - SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, toRecipient.id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, toRecipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp!!, toRecipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp!!, toRecipient.id, System.currentTimeMillis()) } SignalDatabase.messages.setTransactionSuccessful() } finally { @@ -412,45 +427,45 @@ object SyncMessageProcessor { @Throws(MmsException::class) private fun handleSynchronizeSentStoryMessage(envelope: Envelope, sent: Sent) { - log(envelope.timestamp, "Synchronize sent story message for " + sent.timestamp) + log(envelope.timestamp!!, "Synchronize sent story message for " + sent.timestamp) - val manifest = SentStorySyncManifest.fromRecipientsSet(sent.storyMessageRecipientsList) + val manifest = SentStorySyncManifest.fromRecipientsSet(sent.storyMessageRecipients) - if (sent.isRecipientUpdate) { - log(envelope.timestamp, "Processing recipient update for story message and exiting...") - SignalDatabase.storySends.applySentStoryManifest(manifest, sent.timestamp) + if (sent.isRecipientUpdate == true) { + log(envelope.timestamp!!, "Processing recipient update for story message and exiting...") + SignalDatabase.storySends.applySentStoryManifest(manifest, sent.timestamp!!) return } - val storyMessage: StoryMessage = sent.storyMessage + val storyMessage: StoryMessage = sent.storyMessage!! val distributionIds: Set = manifest.getDistributionIdSet() - val groupId: GroupId.V2? = storyMessage.group.groupId + val groupId: GroupId.V2? = storyMessage.group?.groupId val textStoryBody: String? = StoryMessageProcessor.serializeTextAttachment(storyMessage) - val bodyRanges: BodyRangeList? = storyMessage.bodyRangesList.toBodyRangeList() + val bodyRanges: BodyRangeList? = storyMessage.bodyRanges.toBodyRangeList() val storyType: StoryType = storyMessage.type val linkPreviews: List = DataMessageProcessor.getLinkPreviews( - previews = if (storyMessage.textAttachment.hasPreview()) listOf(storyMessage.textAttachment.preview) else emptyList(), + previews = listOfNotNull(storyMessage.textAttachment?.preview), body = "", isStoryEmbed = true ) - val attachments: List = if (storyMessage.hasFileAttachment()) listOfNotNull(storyMessage.fileAttachment.toPointer()) else emptyList() + val attachments: List = listOfNotNull(storyMessage.fileAttachment?.toPointer()) for (distributionId in distributionIds) { val distributionRecipientId = SignalDatabase.distributionLists.getOrCreateByDistributionId(distributionId, manifest) val distributionListRecipient = Recipient.resolved(distributionRecipientId) - insertSentStoryMessage(sent, distributionListRecipient, null, textStoryBody, attachments, sent.timestamp, storyType, linkPreviews, bodyRanges) + insertSentStoryMessage(sent, distributionListRecipient, null, textStoryBody, attachments, sent.timestamp!!, storyType, linkPreviews, bodyRanges) } if (groupId != null) { val groupRecipient: Optional = SignalDatabase.recipients.getByGroupId(groupId) if (groupRecipient.isPresent) { - insertSentStoryMessage(sent, Recipient.resolved(groupRecipient.get()), groupId, textStoryBody, attachments, sent.timestamp, storyType, linkPreviews, bodyRanges) + insertSentStoryMessage(sent, Recipient.resolved(groupRecipient.get()), groupId, textStoryBody, attachments, sent.timestamp!!, storyType, linkPreviews, bodyRanges) } } - SignalDatabase.storySends.applySentStoryManifest(manifest, sent.timestamp) + SignalDatabase.storySends.applySentStoryManifest(manifest, sent.timestamp!!) } @Throws(MmsException::class) @@ -503,8 +518,8 @@ object SyncMessageProcessor { attachments = allAttachments.filterNot { it.isSticker } if (recipient.isSelf) { - SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) } SignalDatabase.messages.setTransactionSuccessful() @@ -527,7 +542,7 @@ object SyncMessageProcessor { return } - val record = SignalDatabase.messages.getMessageFor(sent.timestamp, Recipient.self().id) + val record = SignalDatabase.messages.getMessageFor(sent.timestamp!!, Recipient.self().id) if (record == null) { warn("Got recipient update for non-existing message! Skipping.") return @@ -543,9 +558,9 @@ object SyncMessageProcessor { for (messageRecipientId in messageRecipientIds.keys) { if ((localReceipts[messageRecipientId] ?: GroupReceiptTable.STATUS_UNKNOWN) < GroupReceiptTable.STATUS_UNDELIVERED) { - SignalDatabase.groupReceipts.update(messageRecipientId, messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp) + SignalDatabase.groupReceipts.update(messageRecipientId, messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp!!) } else if (!localReceipts.containsKey(messageRecipientId)) { - SignalDatabase.groupReceipts.insert(listOf(messageRecipientId), messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp) + SignalDatabase.groupReceipts.insert(listOf(messageRecipientId), messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp!!) } } @@ -561,9 +576,9 @@ object SyncMessageProcessor { for (messageRecipientId in messageRecipientIds.keys) { if ((localReceipts[messageRecipientId] ?: GroupReceiptTable.STATUS_UNKNOWN) < GroupReceiptTable.STATUS_UNDELIVERED) { - SignalDatabase.groupReceipts.update(messageRecipientId, messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp) + SignalDatabase.groupReceipts.update(messageRecipientId, messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp!!) } else if (!localReceipts.containsKey(messageRecipientId)) { - SignalDatabase.groupReceipts.insert(listOf(messageRecipientId), messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp) + SignalDatabase.groupReceipts.insert(listOf(messageRecipientId), messageId, GroupReceiptTable.STATUS_UNDELIVERED, sent.timestamp!!) } } @@ -577,7 +592,7 @@ object SyncMessageProcessor { log(envelopeTimestamp, "Synchronize end session message.") val recipient: Recipient = getSyncMessageDestination(sent) - val outgoingEndSessionMessage: OutgoingMessage = endSessionMessage(recipient, sent.timestamp) + val outgoingEndSessionMessage: OutgoingMessage = endSessionMessage(recipient, sent.timestamp!!) val threadId: Long = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) if (!recipient.isGroup) { @@ -599,48 +614,56 @@ object SyncMessageProcessor { @Throws(IOException::class, GroupChangeBusyException::class) private fun handleSynchronizeSentGv2Update(context: Context, envelope: Envelope, sent: Sent) { - log(envelope.timestamp, "Synchronize sent GV2 update for message with timestamp " + sent.timestamp) + log(envelope.timestamp!!, "Synchronize sent GV2 update for message with timestamp " + sent.timestamp!!) - val dataMessage: DataMessage = sent.message - val groupId: GroupId.V2? = dataMessage.groupV2.groupId + val dataMessage: DataMessage = sent.message!! + val groupId: GroupId.V2? = dataMessage.groupV2?.groupId - if (MessageContentProcessor.updateGv2GroupFromServerOrP2PChange(context, envelope.timestamp, dataMessage.groupV2, SignalDatabase.groups.getGroup(GroupId.v2(dataMessage.groupV2.groupMasterKey))) == null) { - log(envelope.timestamp, "Ignoring GV2 message for group we are not currently in $groupId") + if (groupId == null) { + warn(envelope.timestamp!!, "GV2 update missing group id") + return + } + + if (MessageContentProcessor.updateGv2GroupFromServerOrP2PChange(context, envelope.timestamp!!, dataMessage.groupV2!!, SignalDatabase.groups.getGroup(groupId)) == null) { + log(envelope.timestamp!!, "Ignoring GV2 message for group we are not currently in $groupId") } } @Throws(MmsException::class) private fun handleSynchronizeSentExpirationUpdate(sent: Sent, sideEffect: Boolean = false): Long { - log(sent.timestamp, "Synchronize sent expiration update.") + log(sent.timestamp!!, "Synchronize sent expiration update.") val groupId: GroupId? = getSyncMessageDestination(sent).groupId.orNull() if (groupId != null && groupId.isV2) { - warn(sent.timestamp, "Expiration update received for GV2. Ignoring.") + warn(sent.timestamp!!, "Expiration update received for GV2. Ignoring.") return -1 } val recipient: Recipient = getSyncMessageDestination(sent) - val expirationUpdateMessage: OutgoingMessage = expirationUpdateMessage(recipient, if (sideEffect) sent.timestamp - 1 else sent.timestamp, sent.message.expireTimer.seconds.inWholeMilliseconds) + val expirationUpdateMessage: OutgoingMessage = expirationUpdateMessage(recipient, if (sideEffect) sent.timestamp!! - 1 else sent.timestamp!!, sent.message!!.expireTimerDuration.inWholeMilliseconds) val threadId: Long = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) val messageId: Long = SignalDatabase.messages.insertMessageOutbox(expirationUpdateMessage, threadId, false, null) SignalDatabase.messages.markAsSent(messageId, true) - SignalDatabase.recipients.setExpireMessages(recipient.id, sent.message.expireTimer) + SignalDatabase.recipients.setExpireMessages(recipient.id, sent.message!!.expireTimerDuration.inWholeSeconds.toInt()) return threadId } @Throws(MmsException::class, BadGroupIdException::class) private fun handleSynchronizeSentStoryReply(sent: Sent, envelopeTimestamp: Long): Long { - log(envelopeTimestamp, "Synchronize sent story reply for " + sent.timestamp) + log(envelopeTimestamp, "Synchronize sent story reply for " + sent.timestamp!!) try { - val reaction: DataMessage.Reaction = sent.message.reaction + val dataMessage: DataMessage = sent.message!! + val storyContext: DataMessage.StoryContext = dataMessage.storyContext!! + + val reaction: DataMessage.Reaction? = dataMessage.reaction val parentStoryId: ParentStoryId - val authorServiceId: ServiceId = ServiceId.parseOrThrow(sent.message.storyContext.authorAci) - val sentTimestamp: Long = sent.message.storyContext.sentTimestamp + val authorServiceId: ServiceId = ServiceId.parseOrThrow(storyContext.authorAci!!) + val sentTimestamp: Long = storyContext.sentTimestamp!! val recipient: Recipient = getSyncMessageDestination(sent) var quoteModel: QuoteModel? = null var expiresInMillis = 0L @@ -651,16 +674,16 @@ object SyncMessageProcessor { val groupStory: Boolean = threadRecipientId != null && (SignalDatabase.groups.getGroup(threadRecipientId).orNull()?.isActive ?: false) var bodyRanges: BodyRangeList? = null - val body: String? = if (sent.message.hasReaction() && EmojiUtil.isEmoji(reaction.emoji)) { - reaction.emoji - } else if (sent.message.hasBody()) { - bodyRanges = sent.message.bodyRangesList.toBodyRangeList() - sent.message.body + val body: String? = if (EmojiUtil.isEmoji(reaction?.emoji)) { + reaction!!.emoji + } else if (dataMessage.body != null) { + bodyRanges = dataMessage.bodyRanges.toBodyRangeList() + dataMessage.body } else { null } - if (sent.message.hasGroupContext) { + if (dataMessage.hasGroupContext) { parentStoryId = GroupReply(storyMessageId) } else if (groupStory || story.storyType.isStoryWithReplies) { parentStoryId = DirectReply(storyMessageId) @@ -672,7 +695,7 @@ object SyncMessageProcessor { bodyBodyRanges = story.messageRanges } quoteModel = QuoteModel(sentTimestamp, storyAuthorRecipient, quoteBody, false, story.slideDeck.asAttachments(), emptyList(), QuoteModel.Type.NORMAL, bodyBodyRanges) - expiresInMillis = sent.message.expireTimer.seconds.inWholeMilliseconds + expiresInMillis = dataMessage.expireTimerDuration.inWholeMilliseconds } else { warn(envelopeTimestamp, "Story has replies disabled. Dropping reply.") return -1L @@ -681,17 +704,17 @@ object SyncMessageProcessor { val mediaMessage = OutgoingMessage( recipient = recipient, body = body, - timestamp = sent.timestamp, + timestamp = sent.timestamp!!, expiresIn = expiresInMillis, parentStoryId = parentStoryId, - isStoryReaction = sent.message.hasReaction(), + isStoryReaction = reaction != null, quote = quoteModel, - mentions = DataMessageProcessor.getMentions(sent.message.bodyRangesList), + mentions = DataMessageProcessor.getMentions(dataMessage.bodyRanges), bodyRanges = bodyRanges, isSecure = true ) - if (recipient.expiresInSeconds != sent.message.expireTimer) { + if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt()) { handleSynchronizeSentExpirationUpdate(sent, sideEffect = true) } @@ -708,16 +731,16 @@ object SyncMessageProcessor { } SignalDatabase.messages.markAsSent(messageId, true) - if (sent.message.expireTimer > 0) { - SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp) + if (dataMessage.expireTimerDuration > Duration.ZERO) { + SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) ApplicationDependencies .getExpiringMessageManager() - .scheduleDeletion(messageId, true, sent.expirationStartTimestamp, sent.message.expireTimer.seconds.inWholeMilliseconds) + .scheduleDeletion(messageId, true, sent.expirationStartTimestamp ?: 0, dataMessage.expireTimerDuration.inWholeMilliseconds) } if (recipient.isSelf) { - SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) } SignalDatabase.messages.setTransactionSuccessful() } finally { @@ -733,25 +756,26 @@ object SyncMessageProcessor { @Throws(MmsException::class, BadGroupIdException::class) private fun handleSynchronizeSentMediaMessage(context: Context, sent: Sent, envelopeTimestamp: Long): Long { - log(envelopeTimestamp, "Synchronize sent media message for " + sent.timestamp) + log(envelopeTimestamp, "Synchronize sent media message for " + sent.timestamp!!) val recipient: Recipient = getSyncMessageDestination(sent) - val quote: QuoteModel? = DataMessageProcessor.getValidatedQuote(context, envelopeTimestamp, sent.message) - val sticker: Attachment? = DataMessageProcessor.getStickerAttachment(envelopeTimestamp, sent.message) - val sharedContacts: List = DataMessageProcessor.getContacts(sent.message) - val previews: List = DataMessageProcessor.getLinkPreviews(sent.message.previewList, sent.message.body ?: "", false) - val mentions: List = DataMessageProcessor.getMentions(sent.message.bodyRangesList) - val giftBadge: GiftBadge? = if (sent.message.hasGiftBadge()) GiftBadge.newBuilder().setRedemptionToken(sent.message.giftBadge.receiptCredentialPresentation).build() else null - val viewOnce: Boolean = sent.message.isViewOnce - val bodyRanges: BodyRangeList? = sent.message.bodyRangesList.toBodyRangeList() - val syncAttachments: List = listOfNotNull(sticker) + if (viewOnce) listOf(TombstoneAttachment(MediaUtil.VIEW_ONCE, false)) else sent.message.attachmentsList.toPointersWithinLimit() + val dataMessage: DataMessage = sent.message!! + val quote: QuoteModel? = DataMessageProcessor.getValidatedQuote(context, envelopeTimestamp, dataMessage) + val sticker: Attachment? = DataMessageProcessor.getStickerAttachment(envelopeTimestamp, dataMessage) + val sharedContacts: List = DataMessageProcessor.getContacts(dataMessage) + val previews: List = DataMessageProcessor.getLinkPreviews(dataMessage.preview, dataMessage.body ?: "", false) + val mentions: List = DataMessageProcessor.getMentions(dataMessage.bodyRanges) + val giftBadge: GiftBadge? = if (dataMessage.giftBadge?.receiptCredentialPresentation != null) GiftBadge.Builder().redemptionToken(dataMessage.giftBadge!!.receiptCredentialPresentation!!).build() else null + val viewOnce: Boolean = dataMessage.isViewOnce == true + val bodyRanges: BodyRangeList? = dataMessage.bodyRanges.toBodyRangeList() + val syncAttachments: List = listOfNotNull(sticker) + if (viewOnce) listOf(TombstoneAttachment(MediaUtil.VIEW_ONCE, false)) else dataMessage.attachments.toPointersWithinLimit() val mediaMessage = OutgoingMessage( recipient = recipient, - body = sent.message.body ?: "", + body = dataMessage.body ?: "", attachments = syncAttachments, - timestamp = sent.timestamp, - expiresIn = sent.message.expireTimer.seconds.inWholeMilliseconds, + timestamp = sent.timestamp!!, + expiresIn = dataMessage.expireTimerDuration.inWholeMilliseconds, viewOnce = viewOnce, quote = quote, contacts = sharedContacts, @@ -762,7 +786,7 @@ object SyncMessageProcessor { isSecure = true ) - if (recipient.expiresInSeconds != sent.message.expireTimer) { + if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt()) { handleSynchronizeSentExpirationUpdate(sent, sideEffect = true) } @@ -784,14 +808,14 @@ object SyncMessageProcessor { attachments = SignalDatabase.attachments.getAttachmentsForMessage(messageId) - if (sent.message.expireTimer > 0) { - SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp) + if (dataMessage.expireTimerDuration > Duration.ZERO) { + SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) - ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, true, sent.expirationStartTimestamp, sent.message.expireTimer.seconds.inWholeMilliseconds) + ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, true, sent.expirationStartTimestamp ?: 0, dataMessage.expireTimerDuration.inWholeMilliseconds) } if (recipient.isSelf) { - SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) } SignalDatabase.messages.setTransactionSuccessful() } finally { @@ -809,14 +833,15 @@ object SyncMessageProcessor { @Throws(MmsException::class, BadGroupIdException::class) private fun handleSynchronizeSentTextMessage(sent: Sent, envelopeTimestamp: Long): Long { - log(envelopeTimestamp, "Synchronize sent text message for " + sent.timestamp) + log(envelopeTimestamp, "Synchronize sent text message for " + sent.timestamp!!) val recipient = getSyncMessageDestination(sent) - val body = sent.message.body ?: "" - val expiresInMillis = sent.message.expireTimer.seconds.inWholeMilliseconds - val bodyRanges = sent.message.bodyRangesList.filterNot { it.hasMentionAci() }.toBodyRangeList() + val dataMessage: DataMessage = sent.message!! + val body = dataMessage.body ?: "" + val expiresInMillis = dataMessage.expireTimerDuration.inWholeMilliseconds + val bodyRanges = dataMessage.bodyRanges.filter { it.mentionAci == null }.toBodyRangeList() - if (recipient.expiresInSeconds != sent.message.expireTimer) { + if (recipient.expiresInSeconds != dataMessage.expireTimerDuration.inWholeSeconds.toInt()) { handleSynchronizeSentExpirationUpdate(sent, sideEffect = true) } @@ -828,7 +853,7 @@ object SyncMessageProcessor { val outgoingMessage = OutgoingMessage( recipient = recipient, body = body, - timestamp = sent.timestamp, + timestamp = sent.timestamp!!, expiresIn = expiresInMillis, isSecure = true, bodyRanges = bodyRanges @@ -837,20 +862,20 @@ object SyncMessageProcessor { messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null) updateGroupReceiptStatus(sent, messageId, recipient.requireGroupId()) } else { - val outgoingTextMessage = text(threadRecipient = recipient, body = body, expiresIn = expiresInMillis, sentTimeMillis = sent.timestamp, bodyRanges = bodyRanges) + val outgoingTextMessage = text(threadRecipient = recipient, body = body, expiresIn = expiresInMillis, sentTimeMillis = sent.timestamp!!, bodyRanges = bodyRanges) messageId = SignalDatabase.messages.insertMessageOutbox(outgoingTextMessage, threadId, false, null) SignalDatabase.messages.markUnidentified(messageId, sent.isUnidentified(recipient.serviceId.orNull())) } SignalDatabase.threads.update(threadId, true) SignalDatabase.messages.markAsSent(messageId, true) if (expiresInMillis > 0) { - SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp) - ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, isGroup, sent.expirationStartTimestamp, expiresInMillis) + SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0) + ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, isGroup, sent.expirationStartTimestamp ?: 0, expiresInMillis) } if (recipient.isSelf) { - SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp!!, recipient.id, System.currentTimeMillis()) } return threadId @@ -920,13 +945,18 @@ object SyncMessageProcessor { } } - private fun handleSynchronizeViewedMessage(context: Context, viewedMessages: MutableList, envelopeTimestamp: Long) { + private fun handleSynchronizeViewedMessage(context: Context, viewedMessages: List, envelopeTimestamp: Long) { log(envelopeTimestamp, "Synchronize view message. Count: ${viewedMessages.size}, Timestamps: ${viewedMessages.map { it.timestamp }}") val records = viewedMessages .mapNotNull { message -> - val author = Recipient.externalPush(ServiceId.parseOrThrow(message.senderAci)).id - SignalDatabase.messages.getMessageFor(message.timestamp, author) + val author = Recipient.externalPush(ServiceId.parseOrThrow(message.senderAci!!)).id + if (message.timestamp != null) { + SignalDatabase.messages.getMessageFor(message.timestamp!!, author) + } else { + warn(envelopeTimestamp, "Message timestamp null") + null + } } val toMarkViewed = records.map { it.id } @@ -952,8 +982,13 @@ object SyncMessageProcessor { private fun handleSynchronizeViewOnceOpenMessage(context: Context, openMessage: ViewOnceOpen, envelopeTimestamp: Long, earlyMessageCacheEntry: EarlyMessageCacheEntry?) { log(envelopeTimestamp, "Handling a view-once open for message: " + openMessage.timestamp) - val author: RecipientId = Recipient.externalPush(ServiceId.parseOrThrow(openMessage.senderAci)).id - val timestamp: Long = openMessage.timestamp + val author: RecipientId = Recipient.externalPush(ServiceId.parseOrThrow(openMessage.senderAci!!)).id + val timestamp: Long = if (openMessage.timestamp != null) { + openMessage.timestamp!! + } else { + warn(envelopeTimestamp, "Open message missing timestamp") + return + } val record: MessageRecord? = SignalDatabase.messages.getMessageFor(timestamp, author) if (record != null) { @@ -973,7 +1008,7 @@ object SyncMessageProcessor { } } - private fun handleSynchronizeVerifiedMessage(context: Context, verifiedMessage: SignalServiceProtos.Verified) { + private fun handleSynchronizeVerifiedMessage(context: Context, verifiedMessage: Verified) { log("Synchronize verified message.") IdentityUtil.processVerifiedMessage(context, verifiedMessage) @@ -985,14 +1020,13 @@ object SyncMessageProcessor { val jobManager = ApplicationDependencies.getJobManager() for (operation in stickerPackOperations) { - if (operation.hasPackId() && operation.hasPackKey() && operation.hasType()) { - val packId = Hex.toStringCondensed(operation.packId.toByteArray()) - val packKey = Hex.toStringCondensed(operation.packKey.toByteArray()) + if (operation.packId != null && operation.packKey != null && operation.type != null) { + val packId = Hex.toStringCondensed(operation.packId!!.toByteArray()) + val packKey = Hex.toStringCondensed(operation.packKey!!.toByteArray()) - when (operation.type) { + when (operation.type!!) { StickerPackOperation.Type.INSTALL -> jobManager.add(StickerPackDownloadJob.forInstall(packId, packKey, false)) StickerPackOperation.Type.REMOVE -> SignalDatabase.stickers.uninstallPack(packId) - else -> warn("Unknown sticker operation: ${operation.type}") } } else { warn("Received incomplete sticker pack operation sync.") @@ -1003,26 +1037,26 @@ object SyncMessageProcessor { private fun handleSynchronizeConfigurationMessage(context: Context, configurationMessage: Configuration, envelopeTimestamp: Long) { log(envelopeTimestamp, "Synchronize configuration message.") - if (configurationMessage.hasReadReceipts()) { - TextSecurePreferences.setReadReceiptsEnabled(context, configurationMessage.readReceipts) + if (configurationMessage.readReceipts != null) { + TextSecurePreferences.setReadReceiptsEnabled(context, configurationMessage.readReceipts!!) } - if (configurationMessage.hasUnidentifiedDeliveryIndicators()) { - TextSecurePreferences.setShowUnidentifiedDeliveryIndicatorsEnabled(context, configurationMessage.unidentifiedDeliveryIndicators) + if (configurationMessage.unidentifiedDeliveryIndicators != null) { + TextSecurePreferences.setShowUnidentifiedDeliveryIndicatorsEnabled(context, configurationMessage.unidentifiedDeliveryIndicators!!) } - if (configurationMessage.hasTypingIndicators()) { - TextSecurePreferences.setTypingIndicatorsEnabled(context, configurationMessage.typingIndicators) + if (configurationMessage.typingIndicators != null) { + TextSecurePreferences.setTypingIndicatorsEnabled(context, configurationMessage.typingIndicators!!) } - if (configurationMessage.hasLinkPreviews()) { - SignalStore.settings().isLinkPreviewsEnabled = configurationMessage.linkPreviews + if (configurationMessage.linkPreviews != null) { + SignalStore.settings().isLinkPreviewsEnabled = configurationMessage.linkPreviews!! } } private fun handleSynchronizeBlockedListMessage(blockMessage: Blocked) { - val addresses: List = blockMessage.acisList.mapNotNull { SignalServiceAddress.fromRaw(it, null).orNull() } - val groupIds: List = blockMessage.groupIdsList.mapNotNull { it.toByteArray() } + val addresses: List = blockMessage.acis.mapNotNull { SignalServiceAddress.fromRaw(it, null).orNull() } + val groupIds: List = blockMessage.groupIds.map { it.toByteArray() } SignalDatabase.recipients.applyBlockedUpdate(addresses, groupIds) } @@ -1041,10 +1075,10 @@ object SyncMessageProcessor { private fun handleSynchronizeMessageRequestResponse(response: MessageRequestResponse, envelopeTimestamp: Long) { log(envelopeTimestamp, "Synchronize message request response.") - val recipient: Recipient = if (response.hasThreadAci()) { - Recipient.externalPush(ServiceId.parseOrThrow(response.threadAci)) - } else if (response.hasGroupId()) { - val groupId: GroupId = GroupId.push(response.groupId) + val recipient: Recipient = if (response.threadAci != null) { + Recipient.externalPush(ServiceId.parseOrThrow(response.threadAci!!)) + } else if (response.groupId != null) { + val groupId: GroupId = GroupId.push(response.groupId!!) Recipient.externalPossiblyMigratedGroup(groupId) } else { warn("Message request response was missing a thread recipient! Skipping.") @@ -1080,20 +1114,24 @@ object SyncMessageProcessor { } private fun handleSynchronizeOutgoingPayment(outgoingPayment: SyncMessage.OutgoingPayment, envelopeTimestamp: Long) { - if (!outgoingPayment.hasMobileCoin()) { - log("Unknown outgoing payment, ignoring.") + log(envelopeTimestamp, "Synchronize outgoing payment.") + + val mobileCoin = if (outgoingPayment.mobileCoin != null) { + outgoingPayment.mobileCoin!! + } else { + log(envelopeTimestamp, "Unknown outgoing payment, ignoring.") return } var recipientId: RecipientId? = ServiceId.parseOrNull(outgoingPayment.recipientServiceId)?.let { RecipientId.from(it) } - var timestamp = outgoingPayment.mobileCoin.ledgerBlockTimestamp + var timestamp: Long = mobileCoin.ledgerBlockTimestamp ?: 0L if (timestamp == 0L) { timestamp = System.currentTimeMillis() } - var address: MobileCoinPublicAddress? = if (outgoingPayment.mobileCoin.hasRecipientAddress()) { - MobileCoinPublicAddress.fromBytes(outgoingPayment.mobileCoin.recipientAddress.toByteArray()) + var address: MobileCoinPublicAddress? = if (mobileCoin.recipientAddress != null) { + MobileCoinPublicAddress.fromBytes(mobileCoin.recipientAddress!!.toByteArray()) } else { null } @@ -1112,12 +1150,12 @@ object SyncMessageProcessor { recipientId, address!!, timestamp, - outgoingPayment.mobileCoin.ledgerBlockIndex, + mobileCoin.ledgerBlockIndex!!, outgoingPayment.note ?: "", - outgoingPayment.mobileCoin.amountPicoMob.toMobileCoinMoney(), - outgoingPayment.mobileCoin.feePicoMob.toMobileCoinMoney(), - outgoingPayment.mobileCoin.receipt.toByteArray(), - PaymentMetaDataUtil.fromKeysAndImages(outgoingPayment.mobileCoin.outputPublicKeysList, outgoingPayment.mobileCoin.spentKeyImagesList) + mobileCoin.amountPicoMob!!.toMobileCoinMoney(), + mobileCoin.feePicoMob!!.toMobileCoinMoney(), + mobileCoin.receipt!!.toByteArray(), + PaymentMetaDataUtil.fromKeysAndImages(mobileCoin.outputPublicKeys, mobileCoin.spentKeyImages) ) } catch (e: SerializationException) { warn(envelopeTimestamp, "Ignoring synchronized outgoing payment with bad data.", e) @@ -1146,13 +1184,18 @@ object SyncMessageProcessor { return } - val attachment: SignalServiceAttachmentPointer = contactsMessage.blob.toSignalServiceAttachmentPointer() + if (contactsMessage.blob == null) { + log(envelopeTimestamp, "Contact blob is null") + return + } + + val attachment: SignalServiceAttachmentPointer = contactsMessage.blob!!.toSignalServiceAttachmentPointer() ApplicationDependencies.getJobManager().add(MultiDeviceContactSyncJob(attachment)) } private fun handleSynchronizeCallEvent(callEvent: SyncMessage.CallEvent, envelopeTimestamp: Long) { - if (!callEvent.hasId()) { + if (callEvent.id == null) { log(envelopeTimestamp, "Synchronize call event missing call id, ignoring. type: ${callEvent.type}") return } @@ -1168,20 +1211,23 @@ object SyncMessageProcessor { if (callLogEvent.type != CallLogEvent.Type.CLEAR) { log(envelopeTimestamp, "Synchronize call log event has an invalid type ${callLogEvent.type}, ignoring.") return + } else if (callLogEvent.timestamp == null) { + log(envelopeTimestamp, "Synchronize call log event has null timestamp") + return } - SignalDatabase.calls.deleteNonAdHocCallEventsOnOrBefore(callLogEvent.timestamp) - SignalDatabase.callLinks.deleteNonAdminCallLinksOnOrBefore(callLogEvent.timestamp) + SignalDatabase.calls.deleteNonAdHocCallEventsOnOrBefore(callLogEvent.timestamp!!) + SignalDatabase.callLinks.deleteNonAdminCallLinksOnOrBefore(callLogEvent.timestamp!!) } private fun handleSynchronizeCallLink(callLinkUpdate: CallLinkUpdate, envelopeTimestamp: Long) { - if (!callLinkUpdate.hasRootKey()) { + if (callLinkUpdate.rootKey == null) { log(envelopeTimestamp, "Synchronize call link missing root key, ignoring.") return } val callLinkRootKey = try { - CallLinkRootKey(callLinkUpdate.rootKey.toByteArray()) + CallLinkRootKey(callLinkUpdate.rootKey!!.toByteArray()) } catch (e: CallException) { log(envelopeTimestamp, "Synchronize call link has invalid root key, ignoring.") return @@ -1193,7 +1239,7 @@ object SyncMessageProcessor { SignalDatabase.callLinks.updateCallLinkCredentials( roomId, CallLinkCredentials( - callLinkUpdate.rootKey.toByteArray(), + callLinkUpdate.rootKey!!.toByteArray(), callLinkUpdate.adminPassKey?.toByteArray() ) ) @@ -1216,18 +1262,18 @@ object SyncMessageProcessor { } private fun handleSynchronizeOneToOneCallEvent(callEvent: SyncMessage.CallEvent, envelopeTimestamp: Long) { - val callId: Long = callEvent.id - val timestamp: Long = callEvent.timestamp + val callId: Long = callEvent.id!! + val timestamp: Long = callEvent.timestamp ?: 0L val type: CallTable.Type? = CallTable.Type.from(callEvent.type) val direction: CallTable.Direction? = CallTable.Direction.from(callEvent.direction) val event: CallTable.Event? = CallTable.Event.from(callEvent.event) - if (timestamp == 0L || type == null || direction == null || event == null || !callEvent.hasConversationId()) { - warn(envelopeTimestamp, "Call event sync message is not valid, ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + callEvent.hasConversationId()) + if (timestamp == 0L || type == null || direction == null || event == null || callEvent.conversationId == null) { + warn(envelopeTimestamp, "Call event sync message is not valid, ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + (callEvent.conversationId != null)) return } - val aci = ACI.parseOrThrow(callEvent.conversationId) + val aci = ACI.parseOrThrow(callEvent.conversationId!!) val recipientId = RecipientId.from(aci) log(envelopeTimestamp, "Synchronize call event call: $callId") @@ -1256,25 +1302,26 @@ object SyncMessageProcessor { return } - val callId: Long = callEvent.id - val timestamp: Long = callEvent.timestamp + val callId: Long = callEvent.id!! + val timestamp: Long = callEvent.timestamp ?: 0L val type: CallTable.Type? = CallTable.Type.from(callEvent.type) val direction: CallTable.Direction? = CallTable.Direction.from(callEvent.direction) val event: CallTable.Event? = CallTable.Event.from(callEvent.event) + val hasConversationId: Boolean = callEvent.conversationId != null - if (timestamp == 0L || type == null || direction == null || event == null || !callEvent.hasConversationId()) { - warn(envelopeTimestamp, "Group/Ad-hoc call event sync message is not valid, ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + callEvent.hasConversationId()) + if (timestamp == 0L || type == null || direction == null || event == null || !hasConversationId) { + warn(envelopeTimestamp, "Group/Ad-hoc call event sync message is not valid, ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId") return } val recipient: Recipient? = when (type) { CallTable.Type.AD_HOC_CALL -> { - val callLinkRoomId = CallLinkRoomId.fromBytes(callEvent.conversationId.toByteArray()) + val callLinkRoomId = CallLinkRoomId.fromBytes(callEvent.conversationId!!.toByteArray()) val callLink = SignalDatabase.callLinks.getOrCreateCallLinkByRoomId(callLinkRoomId) Recipient.resolved(callLink.recipientId) } CallTable.Type.GROUP_CALL -> { - val groupId: GroupId = GroupId.push(callEvent.conversationId.toByteArray()) + val groupId: GroupId = GroupId.push(callEvent.conversationId!!.toByteArray()) Recipient.externalGroupExact(groupId) } else -> { @@ -1292,14 +1339,14 @@ object SyncMessageProcessor { if (call != null) { if (call.type !== type) { - warn(envelopeTimestamp, "Group/Ad-hoc call event type mismatch, ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + callEvent.hasConversationId()) + warn(envelopeTimestamp, "Group/Ad-hoc call event type mismatch, ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId") return } when (event) { CallTable.Event.DELETE -> SignalDatabase.calls.deleteGroupCall(call) CallTable.Event.ACCEPTED -> { - if (call.timestamp < callEvent.timestamp) { - SignalDatabase.calls.setTimestamp(call.callId, recipient.id, callEvent.timestamp) + if (call.timestamp < timestamp) { + SignalDatabase.calls.setTimestamp(call.callId, recipient.id, timestamp) } if (callEvent.direction == SyncMessage.CallEvent.Direction.INCOMING) { SignalDatabase.calls.acceptIncomingGroupCall(call) @@ -1307,15 +1354,15 @@ object SyncMessageProcessor { warn(envelopeTimestamp, "Invalid direction OUTGOING for event ACCEPTED") } } - CallTable.Event.NOT_ACCEPTED -> warn("Unsupported event type " + event + ". Ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + callEvent.hasConversationId()) - else -> warn("Unsupported event type " + event + ". Ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + callEvent.hasConversationId()) + CallTable.Event.NOT_ACCEPTED -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId") + else -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId") } } else { when (event) { - CallTable.Event.DELETE -> SignalDatabase.calls.insertDeletedGroupCallFromSyncEvent(callEvent.id, recipient.id, direction, timestamp) - CallTable.Event.ACCEPTED -> SignalDatabase.calls.insertAcceptedGroupCall(callEvent.id, recipient.id, direction, timestamp) - CallTable.Event.NOT_ACCEPTED -> warn("Unsupported event type " + event + ". Ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + callEvent.hasConversationId()) - else -> warn("Unsupported event type " + event + ". Ignoring. timestamp: " + timestamp + " type: " + type + " direction: " + direction + " event: " + event + " hasPeer: " + callEvent.hasConversationId()) + CallTable.Event.DELETE -> SignalDatabase.calls.insertDeletedGroupCallFromSyncEvent(callEvent.id!!, recipient.id, direction, timestamp) + CallTable.Event.ACCEPTED -> SignalDatabase.calls.insertAcceptedGroupCall(callEvent.id!!, recipient.id, direction, timestamp) + CallTable.Event.NOT_ACCEPTED -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId") + else -> warn("Unsupported event type $event. Ignoring. timestamp: $timestamp type: $type direction: $direction event: $event hasPeer: $hasConversationId") } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplyUnknownFieldsToSelfMigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplyUnknownFieldsToSelfMigrationJob.java index 26a70fc669..8b80d1d69f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplyUnknownFieldsToSelfMigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplyUnknownFieldsToSelfMigrationJob.java @@ -3,8 +3,6 @@ package org.thoughtcrime.securesms.migrations; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.RecipientTable; import org.thoughtcrime.securesms.database.SignalDatabase; diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java b/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java index e5f9bbfc98..67e26346cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java @@ -17,8 +17,8 @@ import org.thoughtcrime.securesms.util.Base64; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2; +import org.whispersystems.signalservice.internal.push.GroupContext; +import org.whispersystems.signalservice.internal.push.GroupContextV2; import java.io.IOException; import java.util.ArrayList; @@ -40,24 +40,24 @@ public final class MessageGroupContext { this.encodedGroupContext = encodedGroupContext; if (v2) { this.groupV1 = null; - this.groupV2 = new GroupV2Properties(DecryptedGroupV2Context.parseFrom(Base64.decode(encodedGroupContext))); + this.groupV2 = new GroupV2Properties(DecryptedGroupV2Context.ADAPTER.decode(Base64.decode(encodedGroupContext))); this.group = groupV2; } else { - this.groupV1 = new GroupV1Properties(GroupContext.parseFrom(Base64.decode(encodedGroupContext))); + this.groupV1 = new GroupV1Properties(GroupContext.ADAPTER.decode(Base64.decode(encodedGroupContext))); this.groupV2 = null; this.group = groupV1; } } public MessageGroupContext(@NonNull GroupContext group) { - this.encodedGroupContext = Base64.encodeBytes(group.toByteArray()); + this.encodedGroupContext = Base64.encodeBytes(group.encode()); this.groupV1 = new GroupV1Properties(group); this.groupV2 = null; this.group = groupV1; } public MessageGroupContext(@NonNull DecryptedGroupV2Context group) { - this.encodedGroupContext = Base64.encodeBytes(group.toByteArray()); + this.encodedGroupContext = Base64.encodeBytes(group.encode()); this.groupV1 = null; this.groupV2 = new GroupV2Properties(group); this.group = groupV2; @@ -111,24 +111,24 @@ public final class MessageGroupContext { } public boolean isQuit() { - return groupContext.getType().getNumber() == GroupContext.Type.QUIT_VALUE; + return groupContext.type == GroupContext.Type.QUIT; } public boolean isUpdate() { - return groupContext.getType().getNumber() == GroupContext.Type.UPDATE_VALUE; + return groupContext.type == GroupContext.Type.UPDATE; } @Override public @NonNull String getName() { - return groupContext.getName(); + return groupContext.name; } @Override public @NonNull List getMembersListExcludingSelf() { RecipientId selfId = Recipient.self().getId(); - return Stream.of(groupContext.getMembersList()) - .map(GroupContext.Member::getE164) + return Stream.of(groupContext.members) + .map(m -> m.e164) .withoutNulls() .map(RecipientId::fromE164) .filterNot(selfId::equals) @@ -144,9 +144,9 @@ public final class MessageGroupContext { private GroupV2Properties(DecryptedGroupV2Context decryptedGroupV2Context) { this.decryptedGroupV2Context = decryptedGroupV2Context; - this.groupContext = decryptedGroupV2Context.getContext(); + this.groupContext = decryptedGroupV2Context.context; try { - groupMasterKey = new GroupMasterKey(groupContext.getMasterKey().toByteArray()); + groupMasterKey = new GroupMasterKey(groupContext.masterKey.toByteArray()); } catch (InvalidInputException e) { throw new AssertionError(e); } @@ -161,15 +161,15 @@ public final class MessageGroupContext { } public @NonNull DecryptedGroupChange getChange() { - return decryptedGroupV2Context.getChange(); + return decryptedGroupV2Context.change; } public @NonNull List getAllActivePendingAndRemovedMembers() { - DecryptedGroup groupState = decryptedGroupV2Context.getGroupState(); - DecryptedGroupChange groupChange = decryptedGroupV2Context.getChange(); + DecryptedGroup groupState = decryptedGroupV2Context.groupState; + DecryptedGroupChange groupChange = decryptedGroupV2Context.change; - return Stream.of(DecryptedGroupUtil.toAciList(groupState.getMembersList()), - DecryptedGroupUtil.pendingToServiceIdList(groupState.getPendingMembersList()), + return Stream.of(DecryptedGroupUtil.toAciList(groupState.members), + DecryptedGroupUtil.pendingToServiceIdList(groupState.pendingMembers), DecryptedGroupUtil.removedMembersServiceIdList(groupChange), DecryptedGroupUtil.removedPendingMembersServiceIdList(groupChange), DecryptedGroupUtil.removedRequestingMembersServiceIdList(groupChange)) @@ -180,15 +180,15 @@ public final class MessageGroupContext { @Override public @NonNull String getName() { - return decryptedGroupV2Context.getGroupState().getTitle(); + return decryptedGroupV2Context.groupState.title; } @Override public @NonNull List getMembersListExcludingSelf() { - List members = new ArrayList<>(decryptedGroupV2Context.getGroupState().getMembersCount()); + List members = new ArrayList<>(decryptedGroupV2Context.groupState.members.size()); - for (DecryptedMember member : decryptedGroupV2Context.getGroupState().getMembersList()) { - RecipientId recipient = RecipientId.from(ACI.parseOrThrow(member.getAciBytes())); + for (DecryptedMember member : decryptedGroupV2Context.groupState.members) { + RecipientId recipient = RecipientId.from(ACI.parseOrThrow(member.aciBytes)); if (!Recipient.self().getId().equals(recipient)) { members.add(recipient); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/QuoteModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mms/QuoteModel.kt index d72c34b8e9..741b35f1d9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/QuoteModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/QuoteModel.kt @@ -5,7 +5,7 @@ import org.thoughtcrime.securesms.database.model.Mention import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList import org.thoughtcrime.securesms.recipients.RecipientId import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.DataMessage class QuoteModel( val id: Long, @@ -49,8 +49,8 @@ class QuoteModel( return NORMAL } - fun fromProto(type: SignalServiceProtos.DataMessage.Quote.Type): Type { - return if (type == SignalServiceProtos.DataMessage.Quote.Type.GIFT_BADGE) { + fun fromProto(type: DataMessage.Quote.Type?): Type { + return if (type == DataMessage.Quote.Type.GIFT_BADGE) { GIFT_BADGE } else { NORMAL diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt index 412179763a..90bd7b82c2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt @@ -168,7 +168,7 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco .messageRanges .adjustBodyRanges(updated.bodyAdjustments) ?.run { - rangesList + ranges .filter { it.style == BodyRangeList.BodyRange.Style.SPOILER } .sortedBy { it.start } .reversed() diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/CryptoValueUtil.java b/app/src/main/java/org/thoughtcrime/securesms/payments/CryptoValueUtil.java index 7d0e2d3009..dd063112e3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/CryptoValueUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/CryptoValueUtil.java @@ -16,28 +16,21 @@ public final class CryptoValueUtil { } public static @NonNull CryptoValue moneyToCryptoValue(@NonNull Money money) { - CryptoValue.Builder builder = CryptoValue.newBuilder(); + CryptoValue.Builder builder = new CryptoValue.Builder(); if (money instanceof Money.MobileCoin) { Money.MobileCoin mobileCoin = (Money.MobileCoin) money; - builder.setMobileCoinValue(CryptoValue.MobileCoinValue - .newBuilder() - .setPicoMobileCoin(mobileCoin.serializeAmountString())); + builder.mobileCoinValue(new CryptoValue.MobileCoinValue.Builder().picoMobileCoin(mobileCoin.serializeAmountString()).build()); } return builder.build(); } public static @NonNull Money cryptoValueToMoney(@NonNull CryptoValue amount) { - CryptoValue.ValueCase valueCase = amount.getValueCase(); - - switch (valueCase) { - case MOBILECOINVALUE: - return Money.picoMobileCoin(new BigInteger(amount.getMobileCoinValue().getPicoMobileCoin())); - case VALUE_NOT_SET: - throw new AssertionError(); + if (amount.mobileCoinValue != null) { + return Money.picoMobileCoin(new BigInteger(amount.mobileCoinValue.picoMobileCoin)); + } else { + throw new AssertionError(); } - - throw new AssertionError(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinLedgerWrapper.java b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinLedgerWrapper.java index 2d4ff4649c..c58a936605 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinLedgerWrapper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinLedgerWrapper.java @@ -2,8 +2,6 @@ package org.thoughtcrime.securesms.payments; import androidx.annotation.NonNull; -import com.google.protobuf.ByteString; - import org.thoughtcrime.securesms.payments.proto.MobileCoinLedger; import org.whispersystems.signalservice.api.payments.Money; @@ -12,17 +10,19 @@ import java.util.List; import javax.annotation.Nullable; +import okio.ByteString; + public final class MobileCoinLedgerWrapper { private final MobileCoinLedger ledger; private final Balance balance; public MobileCoinLedgerWrapper(@NonNull MobileCoinLedger ledger) { - Money.MobileCoin fullAmount = Money.picoMobileCoin(ledger.getBalance()); - Money.MobileCoin transferableAmount = Money.picoMobileCoin(ledger.getTransferableBalance()); + Money.MobileCoin fullAmount = Money.picoMobileCoin(ledger.balance); + Money.MobileCoin transferableAmount = Money.picoMobileCoin(ledger.transferableBalance); this.ledger = ledger; - this.balance = new Balance(fullAmount, transferableAmount, ledger.getAsOfTimeStamp()); + this.balance = new Balance(fullAmount, transferableAmount, ledger.asOfTimeStamp); } public @NonNull Balance getBalance() { @@ -30,13 +30,13 @@ public final class MobileCoinLedgerWrapper { } public byte[] serialize() { - return ledger.toByteArray(); + return ledger.encode(); } public @NonNull List getAllTxos() { - List txoList = new ArrayList<>(ledger.getSpentTxosCount() + ledger.getUnspentTxosCount()); - addAllMapped(txoList, ledger.getSpentTxosList()); - addAllMapped(txoList, ledger.getUnspentTxosList()); + List txoList = new ArrayList<>(ledger.spentTxos.size() + ledger.unspentTxos.size()); + addAllMapped(txoList, ledger.spentTxos); + addAllMapped(txoList, ledger.unspentTxos); return txoList; } @@ -54,35 +54,35 @@ public final class MobileCoinLedgerWrapper { } public @NonNull Money.MobileCoin getValue() { - return Money.picoMobileCoin(ownedTXO.getAmount()); + return Money.picoMobileCoin(ownedTXO.amount); } public @NonNull ByteString getKeyImage() { - return ownedTXO.getKeyImage(); + return ownedTXO.keyImage; } public @NonNull ByteString getPublicKey() { - return ownedTXO.getPublicKey(); + return ownedTXO.publicKey; } public long getReceivedInBlock() { - return ownedTXO.getReceivedInBlock().getBlockNumber(); + return ownedTXO.receivedInBlock != null ? ownedTXO.receivedInBlock.blockNumber : 0; } public @Nullable Long getSpentInBlock() { - return nullIfZero(ownedTXO.getSpentInBlock().getBlockNumber()); + return ownedTXO.spentInBlock != null ? nullIfZero(ownedTXO.spentInBlock.blockNumber) : null; } public boolean isSpent() { - return ownedTXO.getSpentInBlock().getBlockNumber() != 0; + return ownedTXO.spentInBlock != null && ownedTXO.spentInBlock.blockNumber != 0; } public @Nullable Long getReceivedInBlockTimestamp() { - return nullIfZero(ownedTXO.getReceivedInBlock().getTimestamp()); + return ownedTXO.receivedInBlock != null ? nullIfZero(ownedTXO.receivedInBlock.timestamp) : null; } public @Nullable Long getSpentInBlockTimestamp() { - return nullIfZero(ownedTXO.getSpentInBlock().getTimestamp()); + return ownedTXO.spentInBlock != null ? nullIfZero(ownedTXO.spentInBlock.timestamp) : null; } private @Nullable Long nullIfZero(long value) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtil.java b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtil.java index 26813318a7..d34970a3d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtil.java @@ -2,11 +2,11 @@ package org.thoughtcrime.securesms.payments; import androidx.annotation.NonNull; -import com.google.protobuf.ByteString; - import org.signal.libsignal.protocol.IdentityKey; import org.signal.libsignal.protocol.IdentityKeyPair; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.PaymentAddress; + +import okio.ByteString; public final class MobileCoinPublicAddressProfileUtil { @@ -15,16 +15,17 @@ public final class MobileCoinPublicAddressProfileUtil { /** * Signs the supplied address bytes with the {@link IdentityKeyPair}'s private key and returns a proto that includes it and it's signature. */ - public static @NonNull SignalServiceProtos.PaymentAddress signPaymentsAddress(@NonNull byte[] publicAddressBytes, - @NonNull IdentityKeyPair identityKeyPair) + public static @NonNull PaymentAddress signPaymentsAddress(@NonNull byte[] publicAddressBytes, + @NonNull IdentityKeyPair identityKeyPair) { byte[] signature = identityKeyPair.getPrivateKey().calculateSignature(publicAddressBytes); - return SignalServiceProtos.PaymentAddress.newBuilder() - .setMobileCoinAddress(SignalServiceProtos.PaymentAddress.MobileCoinAddress.newBuilder() - .setAddress(ByteString.copyFrom(publicAddressBytes)) - .setSignature(ByteString.copyFrom(signature))) - .build(); + return new PaymentAddress.Builder() + .mobileCoinAddress(new PaymentAddress.MobileCoinAddress.Builder() + .address(ByteString.of(publicAddressBytes)) + .signature(ByteString.of(signature)) + .build()) + .build(); } /** @@ -32,16 +33,20 @@ public final class MobileCoinPublicAddressProfileUtil { *

* Returns the validated bytes if so, otherwise throws. */ - public static @NonNull byte[] verifyPaymentsAddress(@NonNull SignalServiceProtos.PaymentAddress paymentAddress, + public static @NonNull byte[] verifyPaymentsAddress(@NonNull PaymentAddress paymentAddress, @NonNull IdentityKey identityKey) - throws PaymentsAddressException + throws PaymentsAddressException { - if (!paymentAddress.hasMobileCoinAddress()) { + if (paymentAddress.mobileCoinAddress == null) { throw new PaymentsAddressException(PaymentsAddressException.Code.NO_ADDRESS); } - byte[] bytes = paymentAddress.getMobileCoinAddress().getAddress().toByteArray(); - byte[] signature = paymentAddress.getMobileCoinAddress().getSignature().toByteArray(); + if (paymentAddress.mobileCoinAddress.address == null || paymentAddress.mobileCoinAddress.signature == null) { + throw new PaymentsAddressException(PaymentsAddressException.Code.INVALID_ADDRESS_SIGNATURE); + } + + byte[] bytes = paymentAddress.mobileCoinAddress.address.toByteArray(); + byte[] signature = paymentAddress.mobileCoinAddress.signature.toByteArray(); if (signature.length != 64 || !identityKey.getPublicKey().verifySignature(bytes, signature)) { throw new PaymentsAddressException(PaymentsAddressException.Code.INVALID_ADDRESS_SIGNATURE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/PaymentParcelable.java b/app/src/main/java/org/thoughtcrime/securesms/payments/PaymentParcelable.java index 2d031a0013..7791c2fd98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/PaymentParcelable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/PaymentParcelable.java @@ -6,12 +6,11 @@ import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.InvalidProtocolBufferException; - import org.thoughtcrime.securesms.payments.preferences.model.PayeeParcelable; import org.thoughtcrime.securesms.payments.proto.PaymentMetaData; import org.whispersystems.signalservice.api.payments.Money; +import java.io.IOException; import java.util.UUID; /** @@ -68,7 +67,7 @@ public class PaymentParcelable implements Parcelable { dest.writeString(payment.getNote()); dest.writeString(payment.getAmount().serialize()); dest.writeString(payment.getFee().serialize()); - dest.writeByteArray(payment.getPaymentMetaData().toByteArray()); + dest.writeByteArray(payment.getPaymentMetaData().encode()); dest.writeByte(payment.isSeen() ? (byte) 1 : 0); dest.writeString(payment.getAmountWithDirection().serialize()); dest.writeString(payment.getAmountPlusFeeWithDirection().serialize()); @@ -119,12 +118,12 @@ public class PaymentParcelable implements Parcelable { note = in.readString(); amount = Money.parse(in.readString()); fee = Money.parse(in.readString()); - paymentMetaData = PaymentMetaData.parseFrom(in.createByteArray()); + paymentMetaData = PaymentMetaData.ADAPTER.decode(in.createByteArray()); isSeen = in.readByte() == 1; amountWithDirection = Money.parse(in.readString()); amountPlusFeeWithDirection = Money.parse(in.readString()); isDefrag = in.readByte() == 1; - } catch (Money.ParseException | InvalidProtocolBufferException e) { + } catch (Money.ParseException | IOException e) { throw new IllegalArgumentException(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/ReconstructedPayment.java b/app/src/main/java/org/thoughtcrime/securesms/payments/ReconstructedPayment.java index 8c1be58115..e3d74461e1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/ReconstructedPayment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/ReconstructedPayment.java @@ -84,7 +84,7 @@ public final class ReconstructedPayment implements Payment { @Override public @NonNull PaymentMetaData getPaymentMetaData() { - return PaymentMetaData.getDefaultInstance(); + return new PaymentMetaData(); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java b/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java index 735359cce4..9bed32be43 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java @@ -5,7 +5,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import com.google.protobuf.ByteString; import com.mobilecoin.lib.AccountKey; import com.mobilecoin.lib.AccountSnapshot; import com.mobilecoin.lib.Amount; @@ -52,6 +51,8 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.TimeoutException; +import okio.ByteString; + public final class Wallet { private static final String TAG = Log.tag(Wallet.class); @@ -135,7 +136,7 @@ public final class Wallet { @WorkerThread public @Nullable MobileCoinLedgerWrapper tryGetFullLedger(@Nullable Long minimumBlockIndex) throws IOException, FogSyncException { try { - MobileCoinLedger.Builder builder = MobileCoinLedger.newBuilder(); + MobileCoinLedger.Builder builder = new MobileCoinLedger.Builder(); BigInteger totalUnspent = BigInteger.ZERO; long highestBlockTimeStamp = 0; UnsignedLong highestBlockIndex = UnsignedLong.ZERO; @@ -159,21 +160,23 @@ public final class Wallet { } } + List spentTxos = new LinkedList<>(); + List unspentTxos = new LinkedList<>(); for (OwnedTxOut txOut : accountSnapshot.getAccountActivity().getAllTokenTxOuts(TokenId.MOB)) { final Amount txOutAmount = txOut.getAmount(); - MobileCoinLedger.OwnedTXO.Builder txoBuilder = MobileCoinLedger.OwnedTXO.newBuilder() - .setAmount(Uint64Util.bigIntegerToUInt64(txOutAmount.getValue())) - .setReceivedInBlock(getBlock(txOut.getReceivedBlockIndex(), txOut.getReceivedBlockTimestamp())) - .setKeyImage(ByteString.copyFrom(txOut.getKeyImage().getData())) - .setPublicKey(ByteString.copyFrom(txOut.getPublicKey().getKeyBytes())); + MobileCoinLedger.OwnedTXO.Builder txoBuilder = new MobileCoinLedger.OwnedTXO.Builder() + .amount(Uint64Util.bigIntegerToUInt64(txOutAmount.getValue())) + .receivedInBlock(getBlock(txOut.getReceivedBlockIndex(), txOut.getReceivedBlockTimestamp())) + .keyImage(ByteString.of(txOut.getKeyImage().getData())) + .publicKey(ByteString.of(txOut.getPublicKey().getKeyBytes())); if (txOut.getSpentBlockIndex() != null && (minimumBlockIndex == null || txOut.isSpent(UnsignedLong.valueOf(minimumBlockIndex)))) { - txoBuilder.setSpentInBlock(getBlock(txOut.getSpentBlockIndex(), txOut.getSpentBlockTimestamp())); - builder.addSpentTxos(txoBuilder); + txoBuilder.spentInBlock(getBlock(txOut.getSpentBlockIndex(), txOut.getSpentBlockTimestamp())); + spentTxos.add(txoBuilder.build()); } else { totalUnspent = totalUnspent.add(txOutAmount.getValue()); - builder.addUnspentTxos(txoBuilder); + unspentTxos.add(txoBuilder.build()); } if (txOut.getSpentBlockIndex() != null && txOut.getSpentBlockIndex().compareTo(highestBlockIndex) > 0) { @@ -192,12 +195,16 @@ public final class Wallet { highestBlockTimeStamp = txOut.getReceivedBlockTimestamp().getTime(); } } - builder.setBalance(Uint64Util.bigIntegerToUInt64(totalUnspent)) - .setTransferableBalance(Uint64Util.bigIntegerToUInt64(accountSnapshot.getTransferableAmount(minimumTxFee).getValue())) - .setAsOfTimeStamp(asOfTimestamp) - .setHighestBlock(MobileCoinLedger.Block.newBuilder() - .setBlockNumber(highestBlockIndex.longValue()) - .setTimestamp(highestBlockTimeStamp)); + + builder.spentTxos(spentTxos) + .unspentTxos(unspentTxos) + .balance(Uint64Util.bigIntegerToUInt64(totalUnspent)) + .transferableBalance(Uint64Util.bigIntegerToUInt64(accountSnapshot.getTransferableAmount(minimumTxFee).getValue())) + .asOfTimeStamp(asOfTimestamp) + .highestBlock(new MobileCoinLedger.Block.Builder() + .blockNumber(highestBlockIndex.longValue()) + .timestamp(highestBlockTimeStamp) + .build()); SignalStore.paymentsValues().setEnclaveFailure(false); return new MobileCoinLedgerWrapper(builder.build()); } catch (InvalidFogResponse e) { @@ -220,10 +227,10 @@ public final class Wallet { } private static @Nullable MobileCoinLedger.Block getBlock(@NonNull UnsignedLong blockIndex, @Nullable Date timeStamp) throws Uint64RangeException { - MobileCoinLedger.Block.Builder builder = MobileCoinLedger.Block.newBuilder(); - builder.setBlockNumber(Uint64Util.bigIntegerToUInt64(blockIndex.toBigInteger())); + MobileCoinLedger.Block.Builder builder = new MobileCoinLedger.Block.Builder(); + builder.blockNumber(Uint64Util.bigIntegerToUInt64(blockIndex.toBigInteger())); if (timeStamp != null) { - builder.setTimestamp(timeStamp.getTime()); + builder.timestamp(timeStamp.getTime()); } return builder.build(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcile.java b/app/src/main/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcile.java index 979d3598cd..26afbec741 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcile.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcile.java @@ -6,7 +6,6 @@ import androidx.annotation.WorkerThread; import com.annimon.stream.Collectors; import com.annimon.stream.ComparatorCompat; import com.annimon.stream.Stream; -import com.google.protobuf.ByteString; import org.signal.core.util.MapUtil; import org.signal.core.util.logging.Log; @@ -32,6 +31,8 @@ import java.util.Set; import javax.annotation.Nullable; +import okio.ByteString; + public final class LedgerReconcile { private static final String TAG = Log.tag(LedgerReconcile.class); @@ -53,14 +54,14 @@ public final class LedgerReconcile { @NonNull List allTxOuts) { List nonFailedLocalPayments = Stream.of(allLocalPaymentTransactions).filter(i -> i.getState() != State.FAILED).toList(); - Set allKnownPublicKeys = new HashSet<>(nonFailedLocalPayments.size()); - Set allKnownKeyImages = new HashSet<>(nonFailedLocalPayments.size()); + Set allKnownPublicKeys = new HashSet<>(nonFailedLocalPayments.size()); + Set allKnownKeyImages = new HashSet<>(nonFailedLocalPayments.size()); for (Payment paymentTransaction : nonFailedLocalPayments) { - PaymentMetaData.MobileCoinTxoIdentification txoIdentification = paymentTransaction.getPaymentMetaData().getMobileCoinTxoIdentification(); + PaymentMetaData.MobileCoinTxoIdentification txoIdentification = paymentTransaction.getPaymentMetaData().mobileCoinTxoIdentification; - allKnownPublicKeys.addAll(txoIdentification.getPublicKeyList()); - allKnownKeyImages.addAll(txoIdentification.getKeyImagesList()); + allKnownPublicKeys.addAll(txoIdentification.publicKey); + allKnownKeyImages.addAll(txoIdentification.keyImages); } Set knownTxosByKeyImage = Stream.of(allTxOuts) @@ -120,7 +121,7 @@ public final class LedgerReconcile { private static @NonNull Payment findBlock(@NonNull Payment local, @NonNull Map allTxOuts) { if (local.getDirection().isReceived()) { - for (ByteString publicKey : local.getPaymentMetaData().getMobileCoinTxoIdentification().getPublicKeyList()) { + for (ByteString publicKey : local.getPaymentMetaData().mobileCoinTxoIdentification.publicKey) { MobileCoinLedgerWrapper.OwnedTxo ownedTxo = allTxOuts.get(publicKey); if (ownedTxo != null) { @@ -131,7 +132,7 @@ public final class LedgerReconcile { } } } else { - for (ByteString keyImage : local.getPaymentMetaData().getMobileCoinTxoIdentification().getKeyImagesList()) { + for (ByteString keyImage : local.getPaymentMetaData().mobileCoinTxoIdentification.keyImages) { MobileCoinLedgerWrapper.OwnedTxo ownedTxo = allTxOuts.get(keyImage); if (ownedTxo != null && ownedTxo.getSpentInBlock() != null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCard.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCard.java index 535fe10fdd..46a68de619 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCard.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCard.java @@ -8,7 +8,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; /** * Represents a card showing user details for a recipient under review. - * + *

* See {@link ReviewCardViewHolder} for usage. */ class ReviewCard { @@ -25,11 +25,11 @@ class ReviewCard { @Nullable Action primaryAction, @Nullable Action secondaryAction) { - this.reviewRecipient = reviewRecipient; - this.inCommonGroupsCount = inCommonGroupsCount; - this.cardType = cardType; - this.primaryAction = primaryAction; - this.secondaryAction = secondaryAction; + this.reviewRecipient = reviewRecipient; + this.inCommonGroupsCount = inCommonGroupsCount; + this.cardType = cardType; + this.primaryAction = primaryAction; + this.secondaryAction = secondaryAction; } @NonNull Recipient getReviewRecipient() { @@ -45,10 +45,10 @@ class ReviewCard { } @Nullable ProfileChangeDetails.StringChange getNameChange() { - if (reviewRecipient.getProfileChangeDetails() == null || !reviewRecipient.getProfileChangeDetails().hasProfileNameChange()) { + if (reviewRecipient.getProfileChangeDetails() == null || reviewRecipient.getProfileChangeDetails().profileNameChange == null) { return null; } else { - return reviewRecipient.getProfileChangeDetails().getProfileNameChange(); + return reviewRecipient.getProfileChangeDetails().profileNameChange; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCardViewHolder.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCardViewHolder.java index c92db3f40d..d23d236342 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCardViewHolder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewCardViewHolder.java @@ -91,8 +91,8 @@ class ReviewCardViewHolder extends RecyclerView.ViewHolder { if (reviewCard.getNameChange() != null) { subtextLine2.setText(SpanUtil.italic(context.getString(R.string.ReviewCard__recently_changed, - reviewCard.getNameChange().getPrevious(), - reviewCard.getNameChange().getNew()))); + reviewCard.getNameChange().previous, + reviewCard.getNameChange().newValue))); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewRecipient.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewRecipient.java index ee1f0c6193..fc6df5ca79 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewRecipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewRecipient.java @@ -45,11 +45,11 @@ public class ReviewRecipient { int weight1 = recipient1.getRecipient().getId().equals(alwaysFirstId) ? -100 : 0; int weight2 = recipient2.getRecipient().getId().equals(alwaysFirstId) ? -100 : 0; - if (recipient1.getProfileChangeDetails() != null && recipient1.getProfileChangeDetails().hasProfileNameChange()) { + if (recipient1.getProfileChangeDetails() != null && recipient1.getProfileChangeDetails().profileNameChange != null) { weight1--; } - if (recipient2.getProfileChangeDetails() != null && recipient2.getProfileChangeDetails().hasProfileNameChange()) { + if (recipient2.getProfileChangeDetails() != null && recipient2.getProfileChangeDetails().profileNameChange != null) { weight2--; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java index 0e977ad1a6..9be140aaf5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java @@ -113,7 +113,7 @@ public final class ReviewUtil { private static @NonNull ProfileChangeDetails getProfileChangeDetails(@NonNull MessageRecord messageRecord) { try { - return ProfileChangeDetails.parseFrom(Base64.decode(messageRecord.getBody())); + return ProfileChangeDetails.ADAPTER.decode(Base64.decode(messageRecord.getBody())); } catch (IOException e) { throw new IllegalArgumentException(e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java index d8489cca98..719399e5b2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -6,7 +6,6 @@ import android.net.Uri; import android.text.TextUtils; import androidx.annotation.AnyThread; -import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; @@ -50,9 +49,9 @@ import org.thoughtcrime.securesms.util.AvatarUtil; import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.wallpaper.ChatWallpaper; +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.SignalServiceAddress; import org.whispersystems.signalservice.api.util.OptionalUtil; import org.whispersystems.signalservice.api.util.Preconditions; @@ -1308,15 +1307,15 @@ public class Recipient { } public boolean manuallyShownAvatar() { - return recipientExtras.getManuallyShownAvatar(); + return recipientExtras.manuallyShownAvatar; } public boolean hideStory() { - return recipientExtras.getHideStory(); + return recipientExtras.hideStory; } public boolean hasViewedStory() { - return recipientExtras.getLastStoryView() > 0L; + return recipientExtras.lastStoryView > 0L; } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkRepository.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkRepository.java index 74e3f058ba..bf7b7813ba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkRepository.java @@ -68,8 +68,8 @@ final class ShareableGroupLinkRepository { .get() .requireV2GroupProperties() .getDecryptedGroup() - .getAccessControl() - .getAddFromInviteLink(); + .accessControl + .addFromInviteLink; boolean enabled; boolean approvalNeeded; @@ -77,7 +77,6 @@ final class ShareableGroupLinkRepository { switch (currentState) { case UNKNOWN: case UNSATISFIABLE: - case UNRECOGNIZED: case MEMBER: enabled = false; approvalNeeded = false; diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index 4dc709364d..be8c90db35 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -315,14 +315,17 @@ public class SearchRepository { int startIndex = TextUtils.indexOf(body, cleanSnippet); if (startIndex != -1) { - BodyRangeList.Builder builder = BodyRangeList.newBuilder(); - for (BodyRangeList.BodyRange range : bodyRanges.getRangesList()) { - int adjustedStart = range.getStart() - startIndex + startOffset; - if (adjustedStart >= 0 && adjustedStart + range.getLength() <= bodySnippet.length()) { - builder.addRanges(range.toBuilder().setStart(adjustedStart).build()); + List newRanges = new ArrayList<>(bodyRanges.ranges.size()); + for (BodyRangeList.BodyRange range : bodyRanges.ranges) { + int adjustedStart = range.start - startIndex + startOffset; + if (adjustedStart >= 0 && adjustedStart + range.length <= bodySnippet.length()) { + newRanges.add(range.newBuilder().start(adjustedStart).build()); } } + BodyRangeList.Builder builder = new BodyRangeList.Builder(); + builder.ranges(newRanges); + MessageStyler.style(id, builder.build(), bodySnippet); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallEventSyncMessageUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallEventSyncMessageUtil.kt index 0c2ec36161..399c452778 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallEventSyncMessageUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallEventSyncMessageUtil.kt @@ -1,10 +1,11 @@ package org.thoughtcrime.securesms.service.webrtc -import com.google.protobuf.ByteString +import okio.ByteString +import okio.ByteString.Companion.toByteString import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.ringrtc.RemotePeer -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent +import org.whispersystems.signalservice.internal.push.SyncMessage.CallEvent /** * Helper for creating call event sync messages. @@ -64,18 +65,17 @@ object CallEventSyncMessageUtil { val conversationId: ByteString = when { recipient.isCallLink -> recipient.requireCallLinkRoomId().encodeForProto() - recipient.isGroup -> ByteString.copyFrom(recipient.requireGroupId().decodedId) + recipient.isGroup -> recipient.requireGroupId().decodedId.toByteString() else -> recipient.requireServiceId().toByteString() } - return CallEvent - .newBuilder() - .setConversationId(conversationId) - .setId(callId) - .setTimestamp(timestamp) - .setType(callType) - .setDirection(if (isOutgoing) CallEvent.Direction.OUTGOING else CallEvent.Direction.INCOMING) - .setEvent(event) - .build() + return CallEvent( + conversationId = conversationId, + id = callId, + timestamp = timestamp, + type = callType, + direction = if (isOutgoing) CallEvent.Direction.OUTGOING else CallEvent.Direction.INCOMING, + event = event + ) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index 9cf36e9063..d3b191a0a4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -83,7 +83,7 @@ import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo; import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage; +import org.whispersystems.signalservice.internal.push.SyncMessage; import java.io.IOException; import java.util.Collection; @@ -104,6 +104,7 @@ import java.util.stream.Collectors; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.schedulers.Schedulers; import kotlin.jvm.functions.Function1; +import kotlin.text.Charsets; import static org.thoughtcrime.securesms.events.WebRtcViewModel.GroupCallState.IDLE; import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.CALL_INCOMING; @@ -439,7 +440,7 @@ private void processStateless(@NonNull Function1 members = Stream.of(GroupManager.getUuidCipherTexts(context, groupId)) .map(entry -> new GroupCall.GroupMemberInfo(entry.getKey(), entry.getValue().serialize())) .toList(); - callManager.peekGroupCall(SignalStore.internalValues().groupCallingServer(), credential.getTokenBytes().toByteArray(), members, peekInfo -> { + callManager.peekGroupCall(SignalStore.internalValues().groupCallingServer(), credential.token.getBytes(Charsets.UTF_8), members, peekInfo -> { Long threadId = SignalDatabase.threads().getThreadIdFor(group.getId()); if (threadId != null) { @@ -479,7 +480,7 @@ private void processStateless(@NonNull Function1 receivedGroupCallPeekForRingingCheck(info, peekInfo)); } catch (IOException | VerificationFailedException | CallException e) { @@ -492,7 +493,7 @@ private void processStateless(@NonNull Function1 { try { GroupExternalCredential credential = GroupManager.getGroupExternalCredential(context, groupId); - process((s, p) -> p.handleGroupMembershipProofResponse(s, groupCallHashCode, credential.getTokenBytes().toByteArray())); + process((s, p) -> p.handleGroupMembershipProofResponse(s, groupCallHashCode, credential.token.getBytes(Charsets.UTF_8))); } catch (IOException e) { Log.w(TAG, "Unable to get group membership proof from service", e); process((s, p) -> p.handleGroupCallEnded(s, groupCallHashCode, GroupCall.GroupCallEndReason.SFU_CLIENT_FAILED_TO_JOIN)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java index 9aeb415642..55b9276ed9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java @@ -75,13 +75,11 @@ public class WebRtcData { private final @NonNull byte[] remoteIdentityKey; private final long serverReceivedTimestamp; private final long serverDeliveredTimestamp; - private final boolean isMultiRing; - public ReceivedOfferMetadata(@NonNull byte[] remoteIdentityKey, long serverReceivedTimestamp, long serverDeliveredTimestamp, boolean isMultiRing) { + public ReceivedOfferMetadata(@NonNull byte[] remoteIdentityKey, long serverReceivedTimestamp, long serverDeliveredTimestamp) { this.remoteIdentityKey = remoteIdentityKey; this.serverReceivedTimestamp = serverReceivedTimestamp; this.serverDeliveredTimestamp = serverDeliveredTimestamp; - this.isMultiRing = isMultiRing; } @NonNull byte[] getRemoteIdentityKey() { @@ -95,10 +93,6 @@ public class WebRtcData { long getServerDeliveredTimestamp() { return serverDeliveredTimestamp; } - - boolean isMultiRing() { - return isMultiRing; - } } /** @@ -127,20 +121,14 @@ public class WebRtcData { */ public static class ReceivedAnswerMetadata { private final @NonNull byte[] remoteIdentityKey; - private final boolean isMultiRing; - public ReceivedAnswerMetadata(@NonNull byte[] remoteIdentityKey, boolean isMultiRing) { + public ReceivedAnswerMetadata(@NonNull byte[] remoteIdentityKey) { this.remoteIdentityKey = remoteIdentityKey; - this.isMultiRing = isMultiRing; } @NonNull byte[] getRemoteIdentityKey() { return remoteIdentityKey; } - - boolean isMultiRing() { - return isMultiRing; - } } /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId.kt b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId.kt index c93ae7f4e8..9e55ded332 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/CallLinkRoomId.kt @@ -6,8 +6,9 @@ package org.thoughtcrime.securesms.service.webrtc.links import android.os.Parcelable -import com.google.protobuf.ByteString import kotlinx.parcelize.Parcelize +import okio.ByteString +import okio.ByteString.Companion.toByteString import org.signal.core.util.Serializer import org.signal.ringrtc.CallLinkRootKey import org.thoughtcrime.securesms.util.Base64 @@ -16,7 +17,7 @@ import org.thoughtcrime.securesms.util.Base64 class CallLinkRoomId private constructor(private val roomId: ByteArray) : Parcelable { fun serialize(): String = DatabaseSerializer.serialize(this) - fun encodeForProto(): ByteString = ByteString.copyFrom(roomId) + fun encodeForProto(): ByteString = roomId.toByteString() override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java index c0c89bf1b5..39c6bc938b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java @@ -9,7 +9,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.annimon.stream.Stream; -import com.google.protobuf.InvalidProtocolBufferException; import org.signal.core.util.BreakIteratorCompat; import org.signal.core.util.logging.Log; @@ -24,7 +23,6 @@ import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.ParcelUtil; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.signalservice.api.messages.shared.SharedContact; import java.io.IOException; import java.util.ArrayList; @@ -102,9 +100,9 @@ public final class MultiShareArgs implements Parcelable { try { byte[] data = ParcelUtil.readByteArray(in); if (data != null) { - bodyRanges = BodyRangeList.parseFrom(data); + bodyRanges = BodyRangeList.ADAPTER.decode(data); } - } catch (InvalidProtocolBufferException e) { + } catch (IOException e) { Log.w(TAG, "Invalid body range", e); } this.bodyRanges = bodyRanges; @@ -274,7 +272,7 @@ public final class MultiShareArgs implements Parcelable { } if (bodyRanges != null) { - ParcelUtil.writeByteArray(dest, bodyRanges.toByteArray()); + ParcelUtil.writeByteArray(dest, bodyRanges.encode()); } else { ParcelUtil.writeByteArray(dest, null); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java index bb4742d515..5d432f8f7f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java @@ -390,14 +390,14 @@ public final class MultiShareSender { { return OutgoingMessage.textStoryMessage( recipient, - Base64.encodeBytes(StoryTextPost.newBuilder() - .setBody(getBodyForTextStory(multiShareArgs.getDraftText(), multiShareArgs.getLinkPreview())) - .setStyle(StoryTextPost.Style.DEFAULT) - .setBackground(background.serialize()) - .setTextBackgroundColor(0) - .setTextForegroundColor(Color.WHITE) - .build() - .toByteArray()), + Base64.encodeBytes(new StoryTextPost.Builder() + .body(getBodyForTextStory(multiShareArgs.getDraftText(), multiShareArgs.getLinkPreview())) + .style(StoryTextPost.Style.DEFAULT) + .background(background.serialize()) + .textBackgroundColor(0) + .textForegroundColor(Color.WHITE) + .build() + .encode()), sentTimestamp, storyType.toTextStoryType(), buildLinkPreviews(context, multiShareArgs.getLinkPreview()), diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtil.java b/app/src/main/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtil.java index 51a6b4fc23..8310000211 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtil.java @@ -2,14 +2,12 @@ package org.thoughtcrime.securesms.sms; import androidx.annotation.NonNull; -import com.google.protobuf.ByteString; - import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.thoughtcrime.securesms.mms.MessageGroupContext; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.push.ServiceId; -import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import java.util.Collections; import java.util.Optional; /** @@ -38,13 +36,13 @@ public final class GroupV2UpdateMessageUtil { } private static boolean changeEditorOnlyWasRemoved(@NonNull DecryptedGroupChange decryptedGroupChange) { - return decryptedGroupChange.getDeleteMembersCount() == 1 && - decryptedGroupChange.getDeleteMembers(0).equals(decryptedGroupChange.getEditorServiceIdBytes()); + return decryptedGroupChange.deleteMembers.size() == 1 && + decryptedGroupChange.deleteMembers.get(0).equals(decryptedGroupChange.editorServiceIdBytes); } private static boolean noChangesOtherThanDeletes(@NonNull DecryptedGroupChange decryptedGroupChange) { - DecryptedGroupChange withoutDeletedMembers = decryptedGroupChange.toBuilder() - .clearDeleteMembers() + DecryptedGroupChange withoutDeletedMembers = decryptedGroupChange.newBuilder() + .deleteMembers(Collections.emptyList()) .build(); return DecryptedGroupUtil.changeIsEmpty(withoutDeletedMembers); } @@ -54,7 +52,7 @@ public final class GroupV2UpdateMessageUtil { DecryptedGroupChange decryptedGroupChange = groupContext.requireGroupV2Properties() .getChange(); - return decryptedGroupChange.getDeleteRequestingMembersCount() > 0; + return decryptedGroupChange.deleteRequestingMembers.size() > 0; } return false; @@ -62,14 +60,14 @@ public final class GroupV2UpdateMessageUtil { public static int getChangeRevision(@NonNull MessageGroupContext groupContext) { if (isGroupV2(groupContext) && isUpdate(groupContext)) { - return groupContext.requireGroupV2Properties().getChange().getRevision(); + return groupContext.requireGroupV2Properties().getChange().revision; } return -1; } public static Optional getChangeEditor(MessageGroupContext groupContext) { if (isGroupV2(groupContext) && isUpdate(groupContext)) { - return Optional.ofNullable(groupContext.requireGroupV2Properties().getChange().getEditorServiceIdBytes()).map(ServiceId::parseOrNull); + return Optional.ofNullable(groupContext.requireGroupV2Properties().getChange().editorServiceIdBytes).map(ServiceId::parseOrNull); } return Optional.empty(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java index 6574c539a1..d9836cca68 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java @@ -1,16 +1,11 @@ package org.thoughtcrime.securesms.sms; -import com.google.protobuf.ByteString; - import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context; import org.thoughtcrime.securesms.mms.MessageGroupContext; import org.whispersystems.signalservice.api.push.ServiceId; -import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.Optional; -import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; - public final class IncomingGroupUpdateMessage extends IncomingTextMessage { private final MessageGroupContext groupContext; diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncHelper.java b/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncHelper.java index df0ffdeee6..d889d32e97 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncHelper.java @@ -168,7 +168,7 @@ public final class StorageSyncHelper { if (linkComponents != null) { account.setUsernameLink(new AccountRecord.UsernameLink.Builder() .entropy(ByteString.of(linkComponents.getEntropy())) - .serverId(UuidUtil.toOkioByteString(linkComponents.getServerId())) + .serverId(UuidUtil.toByteString(linkComponents.getServerId())) .color(StorageSyncModels.localToRemoteUsernameColor(SignalStore.misc().getUsernameQrCodeColorScheme())) .build()); } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt index 8b03ca6207..436f551853 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt @@ -48,16 +48,16 @@ data class StoryTextPostModel( ) : Key, Parcelable { override fun updateDiskCacheKey(messageDigest: MessageDigest) { - messageDigest.update(storyTextPost.toByteArray()) + messageDigest.update(storyTextPost.encode()) messageDigest.update(storySentAtMillis.toString().toByteArray()) messageDigest.update(storyAuthor.serialize().toByteArray()) - messageDigest.update(bodyRanges?.toByteArray() ?: ByteArray(0)) + messageDigest.update(bodyRanges?.encode() ?: ByteArray(0)) } val text: String = storyTextPost.body fun getPlaceholder(): Drawable { - return if (storyTextPost.hasBackground()) { + return if (storyTextPost.background != null) { ChatColors.forChatColor(ChatColors.Id.NotSet, storyTextPost.background).chatBubbleMask } else { ColorDrawable(Color.TRANSPARENT) @@ -65,10 +65,10 @@ data class StoryTextPostModel( } override fun writeToParcel(parcel: Parcel, flags: Int) { - ParcelUtil.writeByteArray(parcel, storyTextPost.toByteArray()) + ParcelUtil.writeByteArray(parcel, storyTextPost.encode()) parcel.writeLong(storySentAtMillis) parcel.writeParcelable(storyAuthor, flags) - ParcelUtil.writeByteArray(parcel, bodyRanges?.toByteArray()) + ParcelUtil.writeByteArray(parcel, bodyRanges?.encode()) } override fun describeContents(): Int { @@ -78,10 +78,10 @@ data class StoryTextPostModel( companion object CREATOR : Parcelable.Creator { override fun createFromParcel(parcel: Parcel): StoryTextPostModel { return StoryTextPostModel( - storyTextPost = StoryTextPost.parseFrom(ParcelUtil.readByteArray(parcel)), + storyTextPost = StoryTextPost.ADAPTER.decode(ParcelUtil.readByteArray(parcel)!!), storySentAtMillis = parcel.readLong(), storyAuthor = parcel.readParcelableCompat(RecipientId::class.java)!!, - bodyRanges = ParcelUtil.readByteArray(parcel)?.let { BodyRangeList.parseFrom(it) } + bodyRanges = ParcelUtil.readByteArray(parcel)?.let { BodyRangeList.ADAPTER.decode(it) } ) } @@ -102,7 +102,7 @@ data class StoryTextPostModel( @Throws(IOException::class) fun parseFrom(body: String, storySentAtMillis: Long, storyAuthor: RecipientId, bodyRanges: BodyRangeList?): StoryTextPostModel { return StoryTextPostModel( - storyTextPost = StoryTextPost.parseFrom(Base64.decode(body)), + storyTextPost = StoryTextPost.ADAPTER.decode(Base64.decode(body)), storySentAtMillis = storySentAtMillis, storyAuthor = storyAuthor, bodyRanges = bodyRanges diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt index 4c59544e70..4e8f72042b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt @@ -131,7 +131,7 @@ class StoryTextPostView @JvmOverloads constructor( linkPreviewView.visible = false val font: TextFont = TextFont.fromStyle(storyTextPost.style) - setPostBackground(ChatColors.forChatColor(ChatColors.Id.NotSet, storyTextPost.background).chatBubbleMask) + setPostBackground(ChatColors.forChatColor(ChatColors.Id.NotSet, storyTextPost.background!!).chatBubbleMask) if (font.isAllCaps) { setText(storyTextPost.body.uppercase(Locale.getDefault()), false) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt index 9176875403..27d52b9cfe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt @@ -94,7 +94,7 @@ object StoryContextMenu { fun share(fragment: Fragment, messageRecord: MediaMmsMessageRecord) { val intent = if (messageRecord.storyType.isTextStory) { - val textStoryBody = StoryTextPost.parseFrom(Base64.decode(messageRecord.body)).body + val textStoryBody = StoryTextPost.ADAPTER.decode(Base64.decode(messageRecord.body)).body val linkUrl = messageRecord.linkPreviews.firstOrNull()?.url ?: "" val shareText = "$textStoryBody $linkUrl".trim() diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt index b14435d687..1ab60d3c21 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt @@ -226,7 +226,7 @@ open class StoryViewerPageRepository(context: Context, private val storyViewStat private fun getTextStoryLength(body: String): Int { return if (canParseToTextStory(body)) { val breakIteratorCompat = BreakIteratorCompat.getInstance() - breakIteratorCompat.setText(StoryTextPost.parseFrom(Base64.decode(body)).body) + breakIteratorCompat.setText(StoryTextPost.ADAPTER.decode(Base64.decode(body)).body) breakIteratorCompat.countBreaks() } else { 0 @@ -236,7 +236,7 @@ open class StoryViewerPageRepository(context: Context, private val storyViewStat private fun canParseToTextStory(body: String): Boolean { return if (body.isNotEmpty()) { try { - StoryTextPost.parseFrom(Base64.decode(body)) + StoryTextPost.ADAPTER.decode(Base64.decode(body)) return true } catch (e: Exception) { false diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryPostViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryPostViewModel.kt index 5148444273..8b902d2da7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryPostViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryPostViewModel.kt @@ -81,7 +81,7 @@ class StoryPostViewModel(private val repository: StoryTextPostRepository) : View disposables += Single.zip(typeface, repository.getRecord(recordId), ::Pair).subscribeBy( onSuccess = { (t, record) -> val text: StoryTextPost = if (record.body.isNotEmpty()) { - StoryTextPost.parseFrom(Base64.decode(record.body)) + StoryTextPost.ADAPTER.decode(Base64.decode(record.body)) } else { throw Exception("Text post message body is empty.") } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryTextPostRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryTextPostRepository.kt index 82f2b16598..88e5225f4b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryTextPostRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/post/StoryTextPostRepository.kt @@ -21,7 +21,7 @@ class StoryTextPostRepository { fun getTypeface(recordId: Long): Single { return getRecord(recordId).flatMap { - val model = StoryTextPost.parseFrom(Base64.decode(it.body)) + val model = StoryTextPost.ADAPTER.decode(Base64.decode(it.body)) val textFont = TextFont.fromStyle(model.style) val script = TextToScript.guessScript(model.body) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/EarlyMessageCacheEntry.kt b/app/src/main/java/org/thoughtcrime/securesms/util/EarlyMessageCacheEntry.kt index 9df9c7db3a..4d327f147a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/EarlyMessageCacheEntry.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/EarlyMessageCacheEntry.kt @@ -1,8 +1,8 @@ package org.thoughtcrime.securesms.util import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.Envelope /** * The tuple of information needed to process a message. Used to in [EarlyMessageCache] diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/GroupUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/GroupUtil.java index e569bac54d..3011f8956a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/GroupUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/GroupUtil.java @@ -21,7 +21,8 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.Content; +import org.whispersystems.signalservice.internal.push.GroupContextV2; import java.io.IOException; import java.util.List; @@ -33,17 +34,17 @@ public final class GroupUtil { private static final String TAG = Log.tag(GroupUtil.class); - public static @Nullable SignalServiceProtos.GroupContextV2 getGroupContextIfPresent(@NonNull SignalServiceProtos.Content content) { - if (content.hasDataMessage() && SignalServiceProtoUtil.INSTANCE.getHasGroupContext(content.getDataMessage())) { - return content.getDataMessage().getGroupV2(); - } else if (content.hasSyncMessage() && - content.getSyncMessage().hasSent() && - content.getSyncMessage().getSent().hasMessage() && - SignalServiceProtoUtil.INSTANCE.getHasGroupContext(content.getSyncMessage().getSent().getMessage())) + public static @Nullable GroupContextV2 getGroupContextIfPresent(@NonNull Content content) { + if (content.dataMessage != null && SignalServiceProtoUtil.INSTANCE.getHasGroupContext(content.dataMessage)) { + return content.dataMessage.groupV2; + } else if (content.syncMessage != null && + content.syncMessage.sent != null && + content.syncMessage.sent.message != null && + SignalServiceProtoUtil.INSTANCE.getHasGroupContext(content.syncMessage.sent.message)) { - return content.getSyncMessage().getSent().getMessage().getGroupV2(); - } else if (content.hasStoryMessage() && SignalServiceProtoUtil.INSTANCE.isValid(content.getStoryMessage().getGroup())) { - return content.getStoryMessage().getGroup(); + return content.syncMessage.sent.message.groupV2; + } else if (content.storyMessage != null && SignalServiceProtoUtil.INSTANCE.isValid(content.storyMessage.group)) { + return content.storyMessage.group; } else { return null; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java index 5bf749bfee..a575a01626 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java @@ -40,7 +40,7 @@ import org.whispersystems.signalservice.api.SignalSessionLock; import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.Verified; import java.util.List; import java.util.Optional; @@ -177,12 +177,12 @@ public final class IdentityUtil { } } - public static void processVerifiedMessage(Context context, SignalServiceProtos.Verified verified) throws InvalidKeyException { - SignalServiceAddress destination = new SignalServiceAddress(ServiceId.parseOrThrow(verified.getDestinationAci())); - IdentityKey identityKey = new IdentityKey(verified.getIdentityKey().toByteArray(), 0); + public static void processVerifiedMessage(Context context, Verified verified) throws InvalidKeyException { + SignalServiceAddress destination = new SignalServiceAddress(ServiceId.parseOrThrow(verified.destinationAci)); + IdentityKey identityKey = new IdentityKey(verified.identityKey.toByteArray(), 0); VerifiedMessage.VerifiedState state; - switch (verified.getState()) { + switch (verified.state) { case DEFAULT: state = VerifiedMessage.VerifiedState.DEFAULT; break; diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/MessageRecordUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/util/MessageRecordUtil.kt index 9515b0a55f..06bb92a481 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/MessageRecordUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/MessageRecordUtil.kt @@ -54,7 +54,7 @@ fun MessageRecord.isBorderless(context: Context): Boolean { } fun MessageRecord.hasNoBubble(context: Context): Boolean = - hasSticker() || isBorderless(context) || (isTextOnly(context) && isJumbomoji(context) && (messageRanges?.rangesList?.isEmpty() ?: true)) + hasSticker() || isBorderless(context) || (isTextOnly(context) && isJumbomoji(context) && (messageRanges?.ranges?.isEmpty() ?: true)) fun MessageRecord.hasOnlyThumbnail(context: Context): Boolean { return hasThumbnail() && diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java index 90958d066a..ef75122599 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java @@ -46,7 +46,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.services.ProfileService; import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.internal.ServiceResponse; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.PaymentAddress; import java.io.IOException; import java.util.List; @@ -170,12 +170,12 @@ public final class ProfileUtil { } try { - IdentityKey identityKey = new IdentityKey(Base64.decode(profileAndCredential.getProfile().getIdentityKey()), 0); - ProfileCipher profileCipher = new ProfileCipher(profileKey); - byte[] decrypted = profileCipher.decryptWithLength(encryptedPaymentsAddress); - SignalServiceProtos.PaymentAddress paymentAddress = SignalServiceProtos.PaymentAddress.parseFrom(decrypted); - byte[] bytes = MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(paymentAddress, identityKey); - MobileCoinPublicAddress mobileCoinPublicAddress = MobileCoinPublicAddress.fromBytes(bytes); + IdentityKey identityKey = new IdentityKey(Base64.decode(profileAndCredential.getProfile().getIdentityKey()), 0); + ProfileCipher profileCipher = new ProfileCipher(profileKey); + byte[] decrypted = profileCipher.decryptWithLength(encryptedPaymentsAddress); + PaymentAddress paymentAddress = PaymentAddress.ADAPTER.decode(decrypted); + byte[] bytes = MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(paymentAddress, identityKey); + MobileCoinPublicAddress mobileCoinPublicAddress = MobileCoinPublicAddress.fromBytes(bytes); if (mobileCoinPublicAddress == null) { throw new PaymentsAddressException(PaymentsAddressException.Code.INVALID_ADDRESS); @@ -315,7 +315,7 @@ public final class ProfileUtil { private static void uploadProfile(@NonNull ProfileName profileName, @Nullable String about, @Nullable String aboutEmoji, - @Nullable SignalServiceProtos.PaymentAddress paymentsAddress, + @Nullable PaymentAddress paymentsAddress, @NonNull AvatarUploadParams avatar, @NonNull List badges) throws IOException @@ -354,7 +354,7 @@ public final class ProfileUtil { ApplicationDependencies.getJobManager().add(new RefreshOwnProfileJob()); } - private static @Nullable SignalServiceProtos.PaymentAddress getSelfPaymentsAddressProtobuf() { + private static @Nullable PaymentAddress getSelfPaymentsAddressProtobuf() { if (!SignalStore.paymentsValues().mobileCoinPaymentsEnabled()) { return null; } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFactory.java b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFactory.java index ba95bf9e5f..b741ce5f0c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFactory.java @@ -14,12 +14,12 @@ public final class ChatWallpaperFactory { private ChatWallpaperFactory() {} public static @NonNull ChatWallpaper create(@NonNull Wallpaper model) { - if (model.hasSingleColor()) { - return buildForSingleColor(model.getSingleColor(), model.getDimLevelInDarkTheme()); - } else if (model.hasLinearGradient()) { - return buildForLinearGradinent(model.getLinearGradient(), model.getDimLevelInDarkTheme()); - } else if (model.hasFile()) { - return buildForFile(model.getFile(), model.getDimLevelInDarkTheme()); + if (model.singleColor != null) { + return buildForSingleColor(model.singleColor, model.dimLevelInDarkTheme); + } else if (model.linearGradient != null) { + return buildForLinearGradinent(model.linearGradient, model.dimLevelInDarkTheme); + } else if (model.file_ != null) { + return buildForFile(model.file_, model.dimLevelInDarkTheme); } else { throw new IllegalArgumentException(); } @@ -28,7 +28,7 @@ public final class ChatWallpaperFactory { public static @NonNull ChatWallpaper updateWithDimming(@NonNull ChatWallpaper wallpaper, float dimLevelInDarkTheme) { Wallpaper model = wallpaper.serialize(); - return create(model.toBuilder().setDimLevelInDarkTheme(dimLevelInDarkTheme).build()); + return create(model.newBuilder().dimLevelInDarkTheme(dimLevelInDarkTheme).build()); } public static @NonNull ChatWallpaper create(@NonNull Uri uri) { @@ -36,25 +36,25 @@ public final class ChatWallpaperFactory { } private static @NonNull ChatWallpaper buildForSingleColor(@NonNull Wallpaper.SingleColor singleColor, float dimLevelInDarkTheme) { - return new SingleColorChatWallpaper(singleColor.getColor(), dimLevelInDarkTheme); + return new SingleColorChatWallpaper(singleColor.color, dimLevelInDarkTheme); } private static @NonNull ChatWallpaper buildForLinearGradinent(@NonNull Wallpaper.LinearGradient gradient, float dimLevelInDarkTheme) { - int[] colors = new int[gradient.getColorsCount()]; + int[] colors = new int[gradient.colors.size()]; for (int i = 0; i < colors.length; i++) { - colors[i] = gradient.getColors(i); + colors[i] = gradient.colors.get(i); } - float[] positions = new float[gradient.getPositionsCount()]; + float[] positions = new float[gradient.positions.size()]; for (int i = 0; i < positions.length; i++) { - positions[i] = gradient.getPositions(i); + positions[i] = gradient.positions.get(i); } - return new GradientChatWallpaper(gradient.getRotation(), colors, positions, dimLevelInDarkTheme); + return new GradientChatWallpaper(gradient.rotation, colors, positions, dimLevelInDarkTheme); } private static @NonNull ChatWallpaper buildForFile(@NonNull Wallpaper.File file, float dimLevelInDarkTheme) { - Uri uri = Uri.parse(file.getUri()); + Uri uri = Uri.parse(file.uri); return new UriChatWallpaper(uri, dimLevelInDarkTheme); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/GradientChatWallpaper.java b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/GradientChatWallpaper.java index 66fca85584..e9f1659008 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/GradientChatWallpaper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/GradientChatWallpaper.java @@ -10,7 +10,9 @@ import androidx.annotation.NonNull; import org.thoughtcrime.securesms.components.RotatableGradientDrawable; import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Objects; public final class GradientChatWallpaper implements ChatWallpaper, Parcelable { @@ -112,22 +114,26 @@ public final class GradientChatWallpaper implements ChatWallpaper, Parcelable { @Override public @NonNull Wallpaper serialize() { - Wallpaper.LinearGradient.Builder builder = Wallpaper.LinearGradient.newBuilder(); + Wallpaper.LinearGradient.Builder builder = new Wallpaper.LinearGradient.Builder(); - builder.setRotation(degrees); + builder.rotation(degrees); - for (int color : colors) { - builder.addColors(color); + List colors = new ArrayList<>(this.colors.length); + for (int color : this.colors) { + colors.add(color); } + builder.colors(colors); - for (float position : positions) { - builder.addPositions(position); + List positions = new ArrayList<>(this.positions.length); + for (float position : this.positions) { + positions.add(position); } + builder.positions(positions); - return Wallpaper.newBuilder() - .setLinearGradient(builder) - .setDimLevelInDarkTheme(dimLevelInDarkTheme) - .build(); + return new Wallpaper.Builder() + .linearGradient(builder.build()) + .dimLevelInDarkTheme(dimLevelInDarkTheme) + .build(); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/SingleColorChatWallpaper.java b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/SingleColorChatWallpaper.java index e1a2920a29..442ee16ae6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/SingleColorChatWallpaper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/SingleColorChatWallpaper.java @@ -61,14 +61,14 @@ public final class SingleColorChatWallpaper implements ChatWallpaper, Parcelable @Override public @NonNull Wallpaper serialize() { - Wallpaper.SingleColor.Builder builder = Wallpaper.SingleColor.newBuilder(); + Wallpaper.SingleColor.Builder builder = new Wallpaper.SingleColor.Builder(); - builder.setColor(color); + builder.color(color); - return Wallpaper.newBuilder() - .setSingleColor(builder) - .setDimLevelInDarkTheme(dimLevelInDarkTheme) - .build(); + return new Wallpaper.Builder() + .singleColor(builder.build()) + .dimLevelInDarkTheme(dimLevelInDarkTheme) + .build(); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/UriChatWallpaper.java b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/UriChatWallpaper.java index c079f0b9bd..1517a5a955 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/UriChatWallpaper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/UriChatWallpaper.java @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.wallpaper; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -22,16 +21,11 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.GlideApp; -import org.thoughtcrime.securesms.util.ByteUnit; -import org.thoughtcrime.securesms.util.LRUCache; -import java.util.HashMap; import java.util.Objects; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; final class UriChatWallpaper implements ChatWallpaper, Parcelable { @@ -126,10 +120,10 @@ final class UriChatWallpaper implements ChatWallpaper, Parcelable { @Override public @NonNull Wallpaper serialize() { - return Wallpaper.newBuilder() - .setFile(Wallpaper.File.newBuilder().setUri(uri.toString())) - .setDimLevelInDarkTheme(dimLevelInDarkTheme) - .build(); + return new Wallpaper.Builder() + .file_(new Wallpaper.File.Builder().uri(uri.toString()).build()) + .dimLevelInDarkTheme(dimLevelInDarkTheme) + .build(); } @Override diff --git a/app/src/main/proto/Database.proto b/app/src/main/protowire/Database.proto similarity index 99% rename from app/src/main/proto/Database.proto rename to app/src/main/protowire/Database.proto index 581fd564eb..72a6d18124 100644 --- a/app/src/main/proto/Database.proto +++ b/app/src/main/protowire/Database.proto @@ -40,7 +40,6 @@ message BadgeList { repeated Badge badges = 1; } - import "SignalService.proto"; import "DecryptedGroups.proto"; @@ -68,7 +67,7 @@ message AudioWaveFormData { message ProfileChangeDetails { message StringChange { string previous = 1; - string new = 2; + string newValue = 2; } StringChange profileNameChange = 1; diff --git a/app/src/main/proto/Payments.proto b/app/src/main/protowire/Payments.proto similarity index 92% rename from app/src/main/proto/Payments.proto rename to app/src/main/protowire/Payments.proto index 33f8e50d8b..4872263893 100644 --- a/app/src/main/proto/Payments.proto +++ b/app/src/main/protowire/Payments.proto @@ -31,8 +31,8 @@ message MobileCoinLedger { message PaymentMetaData { message MobileCoinTxoIdentification { - repeated bytes PublicKey = 1; - repeated bytes KeyImages = 2; + repeated bytes publicKey = 1; + repeated bytes keyImages = 2; } MobileCoinTxoIdentification mobileCoinTxoIdentification = 1; diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt index e3a6c2a763..99bee73d83 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt @@ -1,7 +1,7 @@ package org.thoughtcrime.securesms.database import android.database.Cursor -import com.google.protobuf.ByteString +import okio.ByteString import org.signal.core.util.requireBlob import org.signal.spinner.ColumnTransformer import org.signal.storageservice.protos.groups.local.DecryptedBannedMember @@ -19,7 +19,7 @@ object GV2Transformer : ColumnTransformer { override fun transform(tableName: String?, columnName: String, cursor: Cursor): String? { return if (columnName == GroupTable.V2_DECRYPTED_GROUP) { val groupBytes = cursor.requireBlob(GroupTable.V2_DECRYPTED_GROUP) - val group = DecryptedGroup.parseFrom(groupBytes) + val group = DecryptedGroup.ADAPTER.decode(groupBytes!!) group.formatAsHtml() } else { null @@ -28,19 +28,19 @@ object GV2Transformer : ColumnTransformer { } private fun DecryptedGroup.formatAsHtml(): String { - val members: String = describeList(membersList, DecryptedMember::getAciBytes) - val pending: String = describeList(pendingMembersList, DecryptedPendingMember::getServiceIdBytes) - val requesting: String = describeList(requestingMembersList, DecryptedRequestingMember::getAciBytes) - val banned: String = describeList(bannedMembersList, DecryptedBannedMember::getServiceIdBytes) + val members: String = describeList(members, DecryptedMember::aciBytes) + val pending: String = describeList(pendingMembers, DecryptedPendingMember::serviceIdBytes) + val requesting: String = describeList(requestingMembers, DecryptedRequestingMember::aciBytes) + val banned: String = describeList(bannedMembers, DecryptedBannedMember::serviceIdBytes) return """ Revision: $revision Title: $title Avatar: ${(avatar?.length ?: 0) != 0} - Timer: ${disappearingMessagesTimer.duration} + Timer: ${disappearingMessagesTimer!!.duration} Description: "$description" Announcement: $isAnnouncementGroup - Access: attributes(${accessControl.attributes}) members(${accessControl.members}) link(${accessControl.addFromInviteLink}) + Access: attributes(${accessControl!!.attributes}) members(${accessControl!!.members}) link(${accessControl!!.addFromInviteLink}) Members: $members Pending: $pending Requesting: $requesting diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt index d820cef023..870d74e0a9 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt @@ -27,7 +27,7 @@ object GV2UpdateTransformer : ColumnTransformer { return if (MessageTypes.isGroupV2(type) && MessageTypes.isGroupUpdate(type) && body != null) { val decoded = Base64.decode(body) - val decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded) + val decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded) val gv2ChangeDescription: UpdateDescription = MessageRecord.getGv2ChangeDescription(ApplicationDependencies.getApplication(), body, null) "${gv2ChangeDescription.spannable}

${decryptedGroupV2Context.change}" diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageRangesTransformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageRangesTransformer.kt index 4558d35f13..7b728f8081 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageRangesTransformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/MessageRangesTransformer.kt @@ -14,12 +14,12 @@ object MessageRangesTransformer : ColumnTransformer { val messageRangesData: ByteArray? = cursor.requireBlob(MessageTable.MESSAGE_RANGES) return if (messageRangesData != null) { - val ranges = BodyRangeList.parseFrom(messageRangesData) - ranges.rangesList + val ranges = BodyRangeList.ADAPTER.decode(messageRangesData) + ranges.ranges .take(5) .map { range -> - val mention = range.hasMentionUuid() - val style = range.hasStyle() + val mention = range.mentionUuid != null + val style = range.style != null val start = range.start val length = range.length @@ -36,8 +36,8 @@ object MessageRangesTransformer : ColumnTransformer { rangeString }.joinToString("
") .let { - if (ranges.rangesCount > 5) { - it + "
" + "Not showing an additional ${ranges.rangesCount - 5} body ranges." + if (ranges.ranges.size > 5) { + it + "
" + "Not showing an additional ${ranges.ranges.size - 5} body ranges." } else { it } diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/ProfileKeyCredentialTransformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/ProfileKeyCredentialTransformer.kt index c39a1671b7..982e8814ba 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/ProfileKeyCredentialTransformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/ProfileKeyCredentialTransformer.kt @@ -19,7 +19,7 @@ object ProfileKeyCredentialTransformer : ColumnTransformer { override fun transform(tableName: String?, columnName: String, cursor: Cursor): String? { val columnDataString = cursor.requireString(RecipientTable.EXPIRING_PROFILE_KEY_CREDENTIAL) ?: return DefaultColumnTransformer.transform(tableName, columnName, cursor) val columnDataBytes = Base64.decode(columnDataString) - val columnData = ExpiringProfileKeyCredentialColumnData.parseFrom(columnDataBytes) + val columnData = ExpiringProfileKeyCredentialColumnData.ADAPTER.decode(columnDataBytes) val credential = ExpiringProfileKeyCredential(columnData.expiringProfileKeyCredential.toByteArray()) return """ diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/MessageStylerTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/MessageStylerTest.kt index 40474af30d..6bedd4ac42 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/conversation/MessageStylerTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/MessageStylerTest.kt @@ -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 diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/BodyRangeUtilTest.kt b/app/src/test/java/org/thoughtcrime/securesms/database/BodyRangeUtilTest.kt index 5158c106d6..9ddb62cc8d 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/BodyRangeUtilTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/BodyRangeUtilTest.kt @@ -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) } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt b/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt index 815f72dd70..56aa4bca63 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt @@ -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 = extendGroup?.membersList ?: emptyList(), - pendingMembers: List = extendGroup?.pendingMembersList ?: emptyList(), - requestingMembers: List = extendGroup?.requestingMembersList ?: emptyList(), + accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl(), + members: List = extendGroup?.members ?: emptyList(), + pendingMembers: List = extendGroup?.pendingMembers ?: emptyList(), + requestingMembers: List = 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 = emptyList(), pendingMembers: List = emptyList(), requestingMembers: List = 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 = extendGroup?.membersList ?: emptyList(), - pendingMembers: List = extendGroup?.pendingMembersList ?: emptyList(), - requestingMembers: List = extendGroup?.requestingMembersList ?: emptyList(), + accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl(), + members: List = extendGroup?.members ?: emptyList(), + pendingMembers: List = extendGroup?.pendingMembers ?: emptyList(), + requestingMembers: List = 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 = emptyList(), pendingMembers: List = emptyList(), requestingMembers: List = 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 + ) } diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtilTest.java b/app/src/test/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtilTest.java index f18bc0cf69..2cce5d7b5c 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtilTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/database/PaymentMetaDataUtilTest.java @@ -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); } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java b/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java index 284d60c76a..86a926d9bf 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java @@ -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() { diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt b/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt index 22ec8865a3..d0d9a17eb8 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt @@ -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 { 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 { @@ -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 { diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt b/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt index a394701486..df1ea1926f 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt @@ -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)) } } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ChangeBuilder.java b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ChangeBuilder.java index dceab94f0f..add78ddbeb 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ChangeBuilder.java +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ChangeBuilder.java @@ -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; } diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java index bd83bd192e..040ee88c02 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java @@ -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()); } } \ No newline at end of file diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupStateTest.java b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupStateTest.java index 2b75850917..a9565ec8c0 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupStateTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GlobalGroupStateTest.java @@ -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(); } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapperTest.java b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapperTest.java index a9b5401faf..35d81b1cb9 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapperTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupStateMapperTest.java @@ -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) { diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt index acda2ccbaa..c14178cbe7 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt @@ -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()) } 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(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" }) } /** diff --git a/app/src/test/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtilTest.java b/app/src/test/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtilTest.java index c0759a2408..7c6fe5c526 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtilTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/payments/MobileCoinPublicAddressProfileUtilTest.java @@ -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"); } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcileTest.java b/app/src/test/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcileTest.java index 65ed0b80f9..8aecadbc01 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcileTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/payments/reconciliation/LedgerReconcileTest.java @@ -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 payments = reconcile(Collections.emptyList(), new MobileCoinLedgerWrapper(MobileCoinLedger.getDefaultInstance())); + List 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 keyImages, Set 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) { diff --git a/app/src/test/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtilTest.java b/app/src/test/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtilTest.java index c39863cce6..be41c85dbd 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtilTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/sms/GroupV2UpdateMessageUtilTest.java @@ -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); diff --git a/app/src/test/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenuTest.kt b/app/src/test/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenuTest.kt index 887bdf1b3b..43484de257 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenuTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenuTest.kt @@ -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())) ) diff --git a/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt b/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt index 11a5aa0cac..43548159a4 100644 --- a/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt +++ b/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt @@ -1,6 +1,6 @@ package org.thoughtcrime.securesms.database.model.databaseprotos -import com.google.protobuf.ByteString +import okio.ByteString.Companion.toByteString import org.signal.libsignal.zkgroup.groups.GroupMasterKey import org.signal.storageservice.protos.groups.Member import org.signal.storageservice.protos.groups.local.DecryptedGroupChange @@ -9,37 +9,37 @@ import org.signal.storageservice.protos.groups.local.DecryptedPendingMember import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember 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.UUID fun groupContext(masterKey: GroupMasterKey, init: DecryptedGroupV2Context.Builder.() -> Unit): DecryptedGroupV2Context { - val builder = DecryptedGroupV2Context.newBuilder() + val builder = DecryptedGroupV2Context.Builder() builder.context = encryptedGroupContext(masterKey) builder.init() return builder.build() } fun groupChange(editor: ServiceId, init: DecryptedGroupChange.Builder.() -> Unit): DecryptedGroupChange { - val builder = DecryptedGroupChange.newBuilder() + val builder = DecryptedGroupChange.Builder() builder.editorServiceIdBytes = editor.toByteString() builder.init() return builder.build() } -fun encryptedGroupContext(masterKey: GroupMasterKey): SignalServiceProtos.GroupContextV2 { - return SignalServiceProtos.GroupContextV2.newBuilder().setMasterKey(ByteString.copyFrom(masterKey.serialize())).build() +fun encryptedGroupContext(masterKey: GroupMasterKey): GroupContextV2 { + return GroupContextV2.Builder().masterKey(masterKey.serialize().toByteString()).build() } fun DecryptedGroupChange.Builder.addRequestingMember(aci: ACI) { - addNewRequestingMembers(requestingMember(aci)) + newRequestingMembers += requestingMember(aci) } fun DecryptedGroupChange.Builder.deleteRequestingMember(aci: ACI) { - addDeleteRequestingMembers(aci.toByteString()) + deleteRequestingMembers += aci.toByteString() } fun DecryptedGroupChange.Builder.addMember(aci: ACI) { - addNewMembers(member(aci)) + newMembers += member(aci) } fun member(serviceId: UUID, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember { @@ -47,21 +47,21 @@ fun member(serviceId: UUID, role: Member.Role = Member.Role.DEFAULT, joinedAt: I } fun member(aci: ACI, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember { - return DecryptedMember.newBuilder() - .setRole(role) - .setAciBytes(aci.toByteString()) - .setJoinedAtRevision(joinedAt) + return DecryptedMember.Builder() + .role(role) + .aciBytes(aci.toByteString()) + .joinedAtRevision(joinedAt) .build() } fun requestingMember(serviceId: ServiceId): DecryptedRequestingMember { - return DecryptedRequestingMember.newBuilder() - .setAciBytes(serviceId.toByteString()) + return DecryptedRequestingMember.Builder() + .aciBytes(serviceId.toByteString()) .build() } fun pendingMember(serviceId: ServiceId): DecryptedPendingMember { - return DecryptedPendingMember.newBuilder() - .setServiceIdBytes(serviceId.toByteString()) + return DecryptedPendingMember.Builder() + .serviceIdBytes(serviceId.toByteString()) .build() } diff --git a/build.gradle b/build.gradle index 946448e150..fb87ad09cf 100644 --- a/build.gradle +++ b/build.gradle @@ -33,6 +33,7 @@ buildscript { exclude group: 'io.outfoxx', module: 'swiftpoet' } classpath 'androidx.benchmark:benchmark-gradle-plugin:1.1.0-beta04' + classpath files("$rootDir/wire-handler/wire-handler-1.0.0.jar") } } diff --git a/core-util/build.gradle b/core-util/build.gradle index 58d06e30a3..16faf75e25 100644 --- a/core-util/build.gradle +++ b/core-util/build.gradle @@ -1,6 +1,5 @@ plugins { id 'signal-library' - id 'com.google.protobuf' id 'kotlin-kapt' id 'com.squareup.wire' } @@ -9,30 +8,12 @@ android { namespace 'org.signal.core.util' } -protobuf { - protoc { - artifact = 'com.google.protobuf:protoc:3.18.0' - } - generateProtoTasks { - all().each { task -> - task.builtins { - java { - option "lite" - } - } - } - } -} - dependencies { - implementation libs.google.protobuf.javalite implementation libs.androidx.sqlite testImplementation testLibs.junit.junit testImplementation testLibs.mockito.core - testImplementation (testLibs.robolectric.robolectric) { - exclude group: 'com.google.protobuf', module: 'protobuf-java' - } + testImplementation (testLibs.robolectric.robolectric) } wire { diff --git a/core-util/src/main/java/ProtoUtil.kt b/core-util/src/main/java/ProtoUtil.kt new file mode 100644 index 0000000000..0b36206cf5 --- /dev/null +++ b/core-util/src/main/java/ProtoUtil.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +@file:JvmName("ProtoUtil") + +import okio.ByteString + +object ProtoUtil { + + fun ByteString?.isNotEmpty(): Boolean { + return this != null && this.size > 0 + } + + fun ByteString?.isNullOrEmpty(): Boolean { + return this == null || this.size == 0 + } +} diff --git a/core-util/src/main/java/org/signal/core/util/tracing/Tracer.java b/core-util/src/main/java/org/signal/core/util/tracing/Tracer.java index aed2386b8d..98ce13238a 100644 --- a/core-util/src/main/java/org/signal/core/util/tracing/Tracer.java +++ b/core-util/src/main/java/org/signal/core/util/tracing/Tracer.java @@ -5,15 +5,11 @@ import android.os.SystemClock; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.protobuf.ByteString; - -import org.signal.core.util.tracing.TraceProtos.Trace; -import org.signal.core.util.tracing.TraceProtos.TracePacket; -import org.signal.core.util.tracing.TraceProtos.TrackDescriptor; -import org.signal.core.util.tracing.TraceProtos.TrackEvent; - import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Queue; import java.util.UUID; @@ -22,24 +18,26 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import okio.ByteString; + /** * A class to create Perfetto-compatible traces. Currently keeps the entire trace in memory to * avoid weirdness with synchronizing to disk. - * + *

* Some general info on how the Perfetto format works: * - The file format is just a Trace proto (see Trace.proto) * - The Trace proto is just a series of TracePackets * - TracePackets can describe: - * - Threads - * - Start of a method - * - End of a method - * - (And a bunch of other stuff that's not relevant to use at this point) - * + * - Threads + * - Start of a method + * - End of a method + * - (And a bunch of other stuff that's not relevant to use at this point) + *

* We keep a circular buffer of TracePackets for method calls, and we keep a separate list of * TracePackets for threads so we don't lose any of those. - * + *

* Serializing is just a matter of throwing all the TracePackets we have into a proto. - * + *

* Note: This class aims to be largely-thread-safe, but prioritizes speed and memory efficiency * above all else. These methods are going to be called very quickly from every thread imaginable, * and we want to create as little overhead as possible. The idea being that it's ok if we don't, @@ -50,7 +48,7 @@ import java.util.concurrent.atomic.AtomicInteger; public final class Tracer { public static final class TrackId { - public static final long DB_LOCK = -8675309; + public static final long DB_LOCK = -8675309; private static final String DB_LOCK_NAME = "Database Lock"; } @@ -129,19 +127,12 @@ public final class Tracer { } public @NonNull byte[] serialize() { - Trace.Builder trace = Trace.newBuilder(); + List packets = new ArrayList<>(); + packets.addAll(threadPackets.values()); + packets.addAll(eventPackets); + packets.add(forSynchronization(clock.getTimeNanos())); - for (TracePacket thread : threadPackets.values()) { - trace.addPacket(thread); - } - - for (TracePacket event : eventPackets) { - trace.addPacket(event); - } - - trace.addPacket(forSynchronization(clock.getTimeNanos())); - - return trace.build().toByteArray(); + return new Trace.Builder().packet(packets).build().encode(); } /** @@ -149,7 +140,7 @@ public final class Tracer { * The tracking of the event count is not perfectly thread-safe, but doing it in a thread-safe * way would likely involve adding a lock, which we really don't want to do, since it'll add * unnecessary overhead. - * + *

* Note that we keep track of the event count separately because * {@link ConcurrentLinkedQueue#size()} is NOT a constant-time operation. */ @@ -174,57 +165,60 @@ public final class Tracer { } private static TracePacket forTrack(long id, String name) { - return TracePacket.newBuilder() - .setTrustedPacketSequenceId(TRUSTED_SEQUENCE_ID) - .setTrackDescriptor(TrackDescriptor.newBuilder() - .setUuid(id) - .setName(name)) - .build(); + return new TracePacket.Builder() + .trusted_packet_sequence_id(TRUSTED_SEQUENCE_ID) + .track_descriptor(new TrackDescriptor.Builder() + .uuid(id) + .name(name).build()) + .build(); } private static TracePacket forMethodStart(@NonNull String name, long time, long threadId, @Nullable Map values) { - TrackEvent.Builder event = TrackEvent.newBuilder() - .setTrackUuid(threadId) - .setName(name) - .setType(TrackEvent.Type.TYPE_SLICE_BEGIN); + TrackEvent.Builder event = new TrackEvent.Builder() + .track_uuid(threadId) + .name(name) + .type(TrackEvent.Type.TYPE_SLICE_BEGIN); + List debugAnnotations = new LinkedList<>(); if (values != null) { for (Map.Entry entry : values.entrySet()) { - event.addDebugAnnotations(debugAnnotation(entry.getKey(), entry.getValue())); + debugAnnotations.add(debugAnnotation(entry.getKey(), entry.getValue())); } } + event.debug_annotations(debugAnnotations); - return TracePacket.newBuilder() - .setTrustedPacketSequenceId(TRUSTED_SEQUENCE_ID) - .setTimestamp(time) - .setTrackEvent(event) - .build(); + return new TracePacket.Builder() + .trusted_packet_sequence_id(TRUSTED_SEQUENCE_ID) + .timestamp(time) + .track_event(event.build()) + .build(); } - private static TraceProtos.DebugAnnotation debugAnnotation(@NonNull String key, @Nullable String value) { - return TraceProtos.DebugAnnotation.newBuilder() - .setName(key) - .setStringValue(value != null ? value : "") - .build(); + private static DebugAnnotation debugAnnotation(@NonNull String key, @Nullable String value) { + return new DebugAnnotation.Builder() + .name(key) + .string_value(value != null ? value : "") + .build(); } private static TracePacket forMethodEnd(@NonNull String name, long time, long threadId) { - return TracePacket.newBuilder() - .setTrustedPacketSequenceId(TRUSTED_SEQUENCE_ID) - .setTimestamp(time) - .setTrackEvent(TrackEvent.newBuilder() - .setTrackUuid(threadId) - .setName(name) - .setType(TrackEvent.Type.TYPE_SLICE_END)) - .build(); + return new TracePacket.Builder() + .trusted_packet_sequence_id(TRUSTED_SEQUENCE_ID) + .timestamp(time) + .track_event(new TrackEvent.Builder() + .track_uuid(threadId) + .name(name) + .type(TrackEvent.Type.TYPE_SLICE_END) + .build()) + .build(); } private static TracePacket forSynchronization(long time) { - return TracePacket.newBuilder() - .setTrustedPacketSequenceId(TRUSTED_SEQUENCE_ID) - .setTimestamp(time) - .setSynchronizationMarker(ByteString.copyFrom(SYNCHRONIZATION_MARKER)) + return new TracePacket.Builder() + .trusted_packet_sequence_id(TRUSTED_SEQUENCE_ID) + .timestamp(time) + .synchronization_marker(ByteString.of(SYNCHRONIZATION_MARKER)) .build(); } diff --git a/core-util/src/main/proto/Trace.proto b/core-util/src/main/protowire/Trace.proto similarity index 100% rename from core-util/src/main/proto/Trace.proto rename to core-util/src/main/protowire/Trace.proto diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index edbea2401a..127f3003dd 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -2959,6 +2959,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -3628,6 +3633,9 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + @@ -4603,6 +4611,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + diff --git a/libsignal/service/build.gradle b/libsignal/service/build.gradle index 915c6f678e..eb476cdd0a 100644 --- a/libsignal/service/build.gradle +++ b/libsignal/service/build.gradle @@ -3,7 +3,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile apply plugin: 'java-library' apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'java-test-fixtures' -apply plugin: 'com.google.protobuf' apply plugin: 'maven-publish' apply plugin: 'signing' apply plugin: 'idea' @@ -53,7 +52,6 @@ ktlint { } dependencies { - implementation libs.google.protobuf.javalite api libs.google.libphonenumber api libs.jackson.core api libs.jackson.module.kotlin @@ -82,22 +80,9 @@ tasks.whenTaskAdded { task -> } } -protobuf { - protoc { - artifact = 'com.google.protobuf:protoc:3.18.0' - } - generateProtoTasks { - all().each { task -> - task.builtins { - java { - option "lite" - } - } - } - } -} - wire { + protoLibrary = true + kotlin { javaInterop = true } @@ -105,11 +90,15 @@ wire { sourcePath { srcDir 'src/main/protowire' } + + custom { + // Comes from wire-handler jar project + schemaHandlerFactoryClass = "org.signal.wire.Factory" + } } idea { module { - generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java") scopes.COMPILE.plus += [configurations.ideaTestFixturesImplementation] } } diff --git a/libsignal/service/lint.xml b/libsignal/service/lint.xml index 77e44678b3..279cf83162 100644 --- a/libsignal/service/lint.xml +++ b/libsignal/service/lint.xml @@ -3,4 +3,5 @@ + diff --git a/libsignal/service/src/main/java/com/squareup/wire/internal/CountNonDefault.kt b/libsignal/service/src/main/java/com/squareup/wire/internal/CountNonDefault.kt new file mode 100644 index 0000000000..fb9478b551 --- /dev/null +++ b/libsignal/service/src/main/java/com/squareup/wire/internal/CountNonDefault.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package com.squareup.wire.internal + +import okio.ByteString + +/** + * File inspired by countNonNull implementations in com.squareup.wire.internal.Internal.kt + * + * Do not change the name without also updating the name used in wire-handler jar project. Our custom + * handler tweaks the generated proto code to call this less restrictive oneOf validators. Wire requires + * at most one non-null but iOS can't handle that currently, so we use at most one non-null and non-default. + * + * For example, a oneOf property that is an int but set to 0 is valid. + */ + +/** Do not change the name. Returns the number of non-null values in `a, b`. */ +fun countNonDefa(a: Any?, b: Any?): Int { + return a.isNonDefault() + b.isNonDefault() +} + +/** Do not change the name. Returns the number of non-null values in `a, b, c`. */ +fun countNonDefa(a: Any?, b: Any?, c: Any?): Int { + return a.isNonDefault() + b.isNonDefault() + c.isNonDefault() +} + +/** Do not change the name. Returns the number of non-null values in `a, b, c, d, rest`. */ +fun countNonDefa(a: Any?, b: Any?, c: Any?, d: Any?, vararg rest: Any?): Int { + var result = 0 + result += a.isNonDefault() + result += b.isNonDefault() + result += c.isNonDefault() + result += d.isNonDefault() + for (o in rest) { + result += o.isNonDefault() + } + return result +} + +private fun Any?.isNonDefault(): Int { + return when { + this == null -> 0 + this is Boolean && this == false -> 0 + this is ByteString && this.size == 0 -> 0 + this is Byte && this == 0.toByte() -> 0 + this is Short && this == 0.toShort() -> 0 + this is Int && this == 0 -> 0 + this is Long && this == 0L -> 0 + this is String && this == "" -> 0 + this is Double && this == 0.0 -> 0 + this is Float && this == 0f -> 0 + else -> 1 + } +} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java index 87f0c91de7..c4ae426bf5 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java @@ -61,6 +61,7 @@ import org.whispersystems.signalservice.internal.push.BackupAuthCheckRequest; import org.whispersystems.signalservice.internal.push.BackupAuthCheckResponse; import org.whispersystems.signalservice.internal.push.CdsiAuthResponse; import org.whispersystems.signalservice.internal.push.OneTimePreKeyCounts; +import org.whispersystems.signalservice.internal.push.PaymentAddress; import org.whispersystems.signalservice.internal.push.ProfileAvatarData; import org.whispersystems.signalservice.internal.push.ProvisionMessage; import org.whispersystems.signalservice.internal.push.ProvisioningVersion; @@ -68,7 +69,6 @@ import org.whispersystems.signalservice.internal.push.PushServiceSocket; import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse; import org.whispersystems.signalservice.internal.push.RemoteConfigResponse; import org.whispersystems.signalservice.internal.push.ReserveUsernameResponse; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.VerifyAccountResponse; import org.whispersystems.signalservice.internal.push.WhoAmIResponse; import org.whispersystems.signalservice.internal.push.http.ProfileCipherOutputStreamFactory; @@ -730,7 +730,7 @@ public class SignalServiceAccountManager { String name, String about, String aboutEmoji, - Optional paymentsAddress, + Optional paymentsAddress, AvatarUploadParams avatar, List visibleBadgeIds) throws IOException @@ -741,7 +741,7 @@ public class SignalServiceAccountManager { byte[] ciphertextName = profileCipher.encryptString(name, ProfileCipher.getTargetNameLength(name)); byte[] ciphertextAbout = profileCipher.encryptString(about, ProfileCipher.getTargetAboutLength(about)); byte[] ciphertextEmoji = profileCipher.encryptString(aboutEmoji, ProfileCipher.EMOJI_PADDED_LENGTH); - byte[] ciphertextMobileCoinAddress = paymentsAddress.map(address -> profileCipher.encryptWithLength(address.toByteArray(), ProfileCipher.PAYMENTS_ADDRESS_CONTENT_SIZE)).orElse(null); + byte[] ciphertextMobileCoinAddress = paymentsAddress.map(address -> profileCipher.encryptWithLength(address.encode(), ProfileCipher.PAYMENTS_ADDRESS_CONTENT_SIZE)).orElse(null); ProfileAvatarData profileAvatarData = null; if (avatar.stream != null && !avatar.keepTheSame) { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index bcfa22f535..3e6206e930 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -5,8 +5,6 @@ */ package org.whispersystems.signalservice.api; -import com.google.protobuf.ByteString; - import org.signal.libsignal.metadata.certificate.SenderCertificate; import org.signal.libsignal.protocol.IdentityKeyPair; import org.signal.libsignal.protocol.InvalidKeyException; @@ -66,8 +64,8 @@ import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMes import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.DistributionId; -import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; import org.whispersystems.signalservice.api.push.exceptions.MalformedResponseException; @@ -90,35 +88,35 @@ import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableExcept import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration; import org.whispersystems.signalservice.internal.crypto.AttachmentDigest; import org.whispersystems.signalservice.internal.crypto.PaddingInputStream; +import org.whispersystems.signalservice.internal.push.AttachmentPointer; import org.whispersystems.signalservice.internal.push.AttachmentV2UploadAttributes; import org.whispersystems.signalservice.internal.push.AttachmentV4UploadAttributes; +import org.whispersystems.signalservice.internal.push.BodyRange; +import org.whispersystems.signalservice.internal.push.CallMessage; +import org.whispersystems.signalservice.internal.push.Content; +import org.whispersystems.signalservice.internal.push.DataMessage; +import org.whispersystems.signalservice.internal.push.EditMessage; +import org.whispersystems.signalservice.internal.push.GroupContextV2; import org.whispersystems.signalservice.internal.push.GroupMismatchedDevices; import org.whispersystems.signalservice.internal.push.GroupStaleDevices; import org.whispersystems.signalservice.internal.push.MismatchedDevices; +import org.whispersystems.signalservice.internal.push.NullMessage; import org.whispersystems.signalservice.internal.push.OutgoingPushMessage; import org.whispersystems.signalservice.internal.push.OutgoingPushMessageList; +import org.whispersystems.signalservice.internal.push.PniSignatureMessage; +import org.whispersystems.signalservice.internal.push.Preview; import org.whispersystems.signalservice.internal.push.ProvisioningVersion; import org.whispersystems.signalservice.internal.push.PushAttachmentData; import org.whispersystems.signalservice.internal.push.PushServiceSocket; +import org.whispersystems.signalservice.internal.push.ReceiptMessage; import org.whispersystems.signalservice.internal.push.SendGroupMessageResponse; import org.whispersystems.signalservice.internal.push.SendMessageResponse; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.CallMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.EditMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.NullMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Preview; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.ReceiptMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.StoryMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.TextAttachment; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.TypingMessage; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Verified; import org.whispersystems.signalservice.internal.push.StaleDevices; +import org.whispersystems.signalservice.internal.push.StoryMessage; +import org.whispersystems.signalservice.internal.push.SyncMessage; +import org.whispersystems.signalservice.internal.push.TextAttachment; +import org.whispersystems.signalservice.internal.push.TypingMessage; +import org.whispersystems.signalservice.internal.push.Verified; import org.whispersystems.signalservice.internal.push.exceptions.GroupMismatchedDevicesException; import org.whispersystems.signalservice.internal.push.exceptions.GroupStaleDevicesException; import org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException; @@ -153,6 +151,8 @@ import java.util.stream.Collectors; import javax.annotation.Nonnull; +import okio.ByteString; + /** * The main interface for sending Signal Service messages. * @@ -222,8 +222,8 @@ public class SignalServiceMessageSender { Content content = createReceiptContent(message); if (includePniSignature) { - content = content.toBuilder() - .setPniSignatureMessage(createPniSignatureMessage()) + content = content.newBuilder() + .pniSignatureMessage(createPniSignatureMessage()) .build(); } @@ -462,8 +462,8 @@ public class SignalServiceMessageSender { { if (includePniSignature) { Log.d(TAG, "[" + message.getTimestamp() + "] Including PNI signature."); - content = content.toBuilder() - .setPniSignatureMessage(createPniSignatureMessage()) + content = content.newBuilder() + .pniSignatureMessage(createPniSignatureMessage()) .build(); } @@ -509,8 +509,8 @@ public class SignalServiceMessageSender { boolean story) throws IOException { - ByteString distributionBytes = ByteString.copyFrom(message.serialize()); - Content content = Content.newBuilder().setSenderKeyDistributionMessage(distributionBytes).build(); + ByteString distributionBytes = ByteString.of(message.serialize()); + Content content = new Content.Builder().senderKeyDistributionMessage(distributionBytes).build(); EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, groupId); long timestamp = System.currentTimeMillis(); @@ -771,8 +771,8 @@ public class SignalServiceMessageSender { public @Nonnull OutgoingPushMessage getEncryptedSyncPniInitializeDeviceMessage(int deviceId, @Nonnull SyncMessage.PniChangeNumber pniChangeNumber) throws UntrustedIdentityException, IOException, InvalidKeyException { - SyncMessage.Builder syncMessage = createSyncMessageBuilder().setPniChangeNumber(pniChangeNumber); - Content.Builder content = Content.newBuilder().setSyncMessage(syncMessage); + SyncMessage.Builder syncMessage = createSyncMessageBuilder().pniChangeNumber(pniChangeNumber); + Content.Builder content = new Content.Builder().syncMessage(syncMessage.build()); EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content.build(), ContentHint.IMPLICIT, Optional.empty()); return getEncryptedMessage(localAddress, Optional.empty(), deviceId, envelopeContent, false); @@ -886,25 +886,25 @@ public class SignalServiceMessageSender { private SendMessageResult sendVerifiedSyncMessage(VerifiedMessage message) throws IOException, UntrustedIdentityException { - byte[] nullMessageBody = DataMessage.newBuilder() - .setBody(Base64.encodeBytes(Util.getRandomLengthBytes(140))) - .build() - .toByteArray(); + byte[] nullMessageBody = new DataMessage.Builder() + .body(Base64.encodeBytes(Util.getRandomLengthBytes(140))) + .build() + .encode(); - NullMessage nullMessage = NullMessage.newBuilder() - .setPadding(ByteString.copyFrom(nullMessageBody)) + NullMessage nullMessage = new NullMessage.Builder() + .padding(ByteString.of(nullMessageBody)) + .build(); + + Content content = new Content.Builder() + .nullMessage(nullMessage) .build(); - Content content = Content.newBuilder() - .setNullMessage(nullMessage) - .build(); - EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty()); SendMessageResult result = sendMessage(message.getDestination(), Optional.empty(), message.getTimestamp(), envelopeContent, false, null, false, false); if (result.getSuccess().isNeedsSync()) { - Content syncMessage = createMultiDeviceVerifiedContent(message, nullMessage.toByteArray()); + Content syncMessage = createMultiDeviceVerifiedContent(message, nullMessage.encode()); EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.empty()); sendMessage(localAddress, Optional.empty(), message.getTimestamp(), syncMessageContent, false, null, false, false); @@ -916,96 +916,94 @@ public class SignalServiceMessageSender { public SendMessageResult sendNullMessage(SignalServiceAddress address, Optional unidentifiedAccess) throws UntrustedIdentityException, IOException { - byte[] nullMessageBody = DataMessage.newBuilder() - .setBody(Base64.encodeBytes(Util.getRandomLengthBytes(140))) - .build() - .toByteArray(); + byte[] nullMessageBody = new DataMessage.Builder() + .body(Base64.encodeBytes(Util.getRandomLengthBytes(140))) + .build() + .encode(); - NullMessage nullMessage = NullMessage.newBuilder() - .setPadding(ByteString.copyFrom(nullMessageBody)) + NullMessage nullMessage = new NullMessage.Builder() + .padding(ByteString.of(nullMessageBody)) + .build(); + + Content content = new Content.Builder() + .nullMessage(nullMessage) .build(); - Content content = Content.newBuilder() - .setNullMessage(nullMessage) - .build(); - EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty()); return sendMessage(address, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, false, false); } - private SignalServiceProtos.PniSignatureMessage createPniSignatureMessage() { + private PniSignatureMessage createPniSignatureMessage() { byte[] signature = localPniIdentity.signAlternateIdentity(aciStore.getIdentityKeyPair().getPublicKey()); - return SignalServiceProtos.PniSignatureMessage.newBuilder() - .setPni(UuidUtil.toByteString(localPni.getRawUuid())) - .setSignature(ByteString.copyFrom(signature)) - .build(); + return new PniSignatureMessage.Builder() + .pni(UuidUtil.toByteString(localPni.getRawUuid())) + .signature(ByteString.of(signature)) + .build(); } private Content createTypingContent(SignalServiceTypingMessage message) { - Content.Builder container = Content.newBuilder(); - TypingMessage.Builder builder = TypingMessage.newBuilder(); + Content.Builder container = new Content.Builder(); + TypingMessage.Builder builder = new TypingMessage.Builder(); - builder.setTimestamp(message.getTimestamp()); + builder.timestamp(message.getTimestamp()); - if (message.isTypingStarted()) builder.setAction(TypingMessage.Action.STARTED); - else if (message.isTypingStopped()) builder.setAction(TypingMessage.Action.STOPPED); + if (message.isTypingStarted()) builder.action(TypingMessage.Action.STARTED); + else if (message.isTypingStopped()) builder.action(TypingMessage.Action.STOPPED); else throw new IllegalArgumentException("Unknown typing indicator"); if (message.getGroupId().isPresent()) { - builder.setGroupId(ByteString.copyFrom(message.getGroupId().get())); + builder.groupId(ByteString.of(message.getGroupId().get())); } - return container.setTypingMessage(builder).build(); + return container.typingMessage(builder.build()).build(); } private Content createStoryContent(SignalServiceStoryMessage message) throws IOException { - Content.Builder container = Content.newBuilder(); - StoryMessage.Builder builder = StoryMessage.newBuilder(); + Content.Builder container = new Content.Builder(); + StoryMessage.Builder builder = new StoryMessage.Builder(); if (message.getProfileKey().isPresent()) { - builder.setProfileKey(ByteString.copyFrom(message.getProfileKey().get())); + builder.profileKey(ByteString.of(message.getProfileKey().get())); } if (message.getGroupContext().isPresent()) { - builder.setGroup(createGroupContent(message.getGroupContext().get())); + builder.group(createGroupContent(message.getGroupContext().get())); } if (message.getFileAttachment().isPresent()) { if (message.getFileAttachment().get().isStream()) { - builder.setFileAttachment(createAttachmentPointer(message.getFileAttachment().get().asStream())); + builder.fileAttachment(createAttachmentPointer(message.getFileAttachment().get().asStream())); } else { - builder.setFileAttachment(createAttachmentPointer(message.getFileAttachment().get().asPointer())); + builder.fileAttachment(createAttachmentPointer(message.getFileAttachment().get().asPointer())); } } if (message.getTextAttachment().isPresent()) { - builder.setTextAttachment(createTextAttachment(message.getTextAttachment().get())); + builder.textAttachment(createTextAttachment(message.getTextAttachment().get())); } if (message.getBodyRanges().isPresent()) { - builder.addAllBodyRanges(message.getBodyRanges().get()); + builder.bodyRanges(message.getBodyRanges().get()); } - builder.setAllowsReplies(message.getAllowsReplies().orElse(true)); + builder.allowsReplies(message.getAllowsReplies().orElse(true)); - return container.setStoryMessage(builder).build(); + return container.storyMessage(builder.build()).build(); } private Content createReceiptContent(SignalServiceReceiptMessage message) { - Content.Builder container = Content.newBuilder(); - ReceiptMessage.Builder builder = ReceiptMessage.newBuilder(); + Content.Builder container = new Content.Builder(); + ReceiptMessage.Builder builder = new ReceiptMessage.Builder(); - for (long timestamp : message.getTimestamps()) { - builder.addTimestamp(timestamp); - } + builder.timestamp = message.getTimestamps(); - if (message.isDeliveryReceipt()) builder.setType(ReceiptMessage.Type.DELIVERY); - else if (message.isReadReceipt()) builder.setType(ReceiptMessage.Type.READ); - else if (message.isViewedReceipt()) builder.setType(ReceiptMessage.Type.VIEWED); + if (message.isDeliveryReceipt()) builder.type(ReceiptMessage.Type.DELIVERY); + else if (message.isReadReceipt()) builder.type(ReceiptMessage.Type.READ); + else if (message.isViewedReceipt()) builder.type(ReceiptMessage.Type.VIEWED); - return container.setReceiptMessage(builder).build(); + return container.receiptMessage(builder.build()).build(); } private Content createMessageContent(SentTranscriptMessage transcriptMessage) throws IOException { @@ -1021,180 +1019,195 @@ public class SignalServiceMessageSender { } private Content createMessageContent(SignalServiceDataMessage message) throws IOException { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); DataMessage.Builder dataMessage = createDataMessage(message); - return enforceMaxContentSize(container.setDataMessage(dataMessage).build()); + return enforceMaxContentSize(container.dataMessage(dataMessage.build()).build()); } private Content createEditMessageContent(SignalServiceEditMessage editMessage) throws IOException { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); DataMessage.Builder dataMessage = createDataMessage(editMessage.getDataMessage()); - EditMessage.Builder editMessageProto = EditMessage.newBuilder() - .setDataMessage(dataMessage) - .setTargetSentTimestamp(editMessage.getTargetSentTimestamp()); + EditMessage.Builder editMessageProto = new EditMessage.Builder() + .dataMessage(dataMessage.build()) + .targetSentTimestamp(editMessage.getTargetSentTimestamp()); - return enforceMaxContentSize(container.setEditMessage(editMessageProto).build()); + return enforceMaxContentSize(container.editMessage(editMessageProto.build()).build()); } private DataMessage.Builder createDataMessage(SignalServiceDataMessage message) throws IOException { - DataMessage.Builder builder = DataMessage.newBuilder(); - List pointers = createAttachmentPointers(message.getAttachments()); + DataMessage.Builder builder = new DataMessage.Builder(); + List pointers = createAttachmentPointers(message.getAttachments()); + + builder.requiredProtocolVersion = 0; if (!pointers.isEmpty()) { - builder.addAllAttachments(pointers); + builder.attachments(pointers); for (AttachmentPointer pointer : pointers) { - if (pointer.getAttachmentIdentifierCase() == AttachmentPointer.AttachmentIdentifierCase.CDNKEY || pointer.getCdnNumber() != 0) { - builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.CDN_SELECTOR_ATTACHMENTS_VALUE, builder.getRequiredProtocolVersion())); - break; - } + // TODO [cody] wire +// if (pointer.getAttachmentIdentifierCase() == AttachmentPointer.AttachmentIdentifierCase.CDNKEY || pointer.getCdnNumber() != 0) { +// builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.CDN_SELECTOR_ATTACHMENTS_VALUE, builder.getRequiredProtocolVersion())); +// break; +// } } } if (message.getBody().isPresent()) { - builder.setBody(message.getBody().get()); + builder.body(message.getBody().get()); } if (message.getGroupContext().isPresent()) { - builder.setGroupV2(createGroupContent(message.getGroupContext().get())); + builder.groupV2(createGroupContent(message.getGroupContext().get())); } if (message.isEndSession()) { - builder.setFlags(DataMessage.Flags.END_SESSION_VALUE); + builder.flags(DataMessage.Flags.END_SESSION.getValue()); } if (message.isExpirationUpdate()) { - builder.setFlags(DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE); + builder.flags(DataMessage.Flags.EXPIRATION_TIMER_UPDATE.getValue()); } if (message.isProfileKeyUpdate()) { - builder.setFlags(DataMessage.Flags.PROFILE_KEY_UPDATE_VALUE); + builder.flags(DataMessage.Flags.PROFILE_KEY_UPDATE.getValue()); } if (message.getExpiresInSeconds() > 0) { - builder.setExpireTimer(message.getExpiresInSeconds()); + builder.expireTimer(message.getExpiresInSeconds()); } if (message.getProfileKey().isPresent()) { - builder.setProfileKey(ByteString.copyFrom(message.getProfileKey().get())); + builder.profileKey(ByteString.of(message.getProfileKey().get())); } if (message.getQuote().isPresent()) { - DataMessage.Quote.Builder quoteBuilder = DataMessage.Quote.newBuilder() - .setId(message.getQuote().get().getId()) - .setText(message.getQuote().get().getText()) - .setAuthorAci(message.getQuote().get().getAuthor().toString()) - .setType(message.getQuote().get().getType().getProtoType()); + DataMessage.Quote.Builder quoteBuilder = new DataMessage.Quote.Builder() + .id(message.getQuote().get().getId()) + .text(message.getQuote().get().getText()) + .authorAci(message.getQuote().get().getAuthor().toString()) + .type(message.getQuote().get().getType().getProtoType()); List mentions = message.getQuote().get().getMentions(); if (mentions != null && !mentions.isEmpty()) { + List bodyRanges = new ArrayList<>(quoteBuilder.bodyRanges); for (SignalServiceDataMessage.Mention mention : mentions) { - quoteBuilder.addBodyRanges(BodyRange.newBuilder() - .setStart(mention.getStart()) - .setLength(mention.getLength()) - .setMentionAci(mention.getServiceId().toString())); + bodyRanges.add(new BodyRange.Builder() + .start(mention.getStart()) + .length(mention.getLength()) + .mentionAci(mention.getServiceId().toString()) + .build()); } + builder.bodyRanges(bodyRanges); - builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.MENTIONS_VALUE, builder.getRequiredProtocolVersion())); + builder.requiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.MENTIONS.getValue(), builder.requiredProtocolVersion)); } List bodyRanges = message.getQuote().get().getBodyRanges(); if (bodyRanges != null) { - quoteBuilder.addAllBodyRanges(bodyRanges); + List quoteBodyRanges = new ArrayList<>(quoteBuilder.bodyRanges); + quoteBodyRanges.addAll(bodyRanges); + quoteBuilder.bodyRanges(quoteBodyRanges); } List attachments = message.getQuote().get().getAttachments(); if (attachments != null) { + List quotedAttachments = new ArrayList<>(attachments.size()); for (SignalServiceDataMessage.Quote.QuotedAttachment attachment : attachments) { - DataMessage.Quote.QuotedAttachment.Builder quotedAttachment = DataMessage.Quote.QuotedAttachment.newBuilder(); + DataMessage.Quote.QuotedAttachment.Builder quotedAttachment = new DataMessage.Quote.QuotedAttachment.Builder(); - quotedAttachment.setContentType(attachment.getContentType()); + quotedAttachment.contentType(attachment.getContentType()); if (attachment.getFileName() != null) { - quotedAttachment.setFileName(attachment.getFileName()); + quotedAttachment.fileName(attachment.getFileName()); } if (attachment.getThumbnail() != null) { - quotedAttachment.setThumbnail(createAttachmentPointer(attachment.getThumbnail().asStream())); + quotedAttachment.thumbnail(createAttachmentPointer(attachment.getThumbnail().asStream())); } - quoteBuilder.addAttachments(quotedAttachment); + quotedAttachments.add(quotedAttachment.build()); } + quoteBuilder.attachments(quotedAttachments); } - builder.setQuote(quoteBuilder); + builder.quote(quoteBuilder.build()); } if (message.getSharedContacts().isPresent()) { - builder.addAllContact(createSharedContactContent(message.getSharedContacts().get())); + builder.contact = createSharedContactContent(message.getSharedContacts().get()); } if (message.getPreviews().isPresent()) { + List previews = new ArrayList<>(message.getPreviews().get().size()); for (SignalServicePreview preview : message.getPreviews().get()) { - builder.addPreview(createPreview(preview)); + previews.add(createPreview(preview)); } + builder.preview(previews); } if (message.getMentions().isPresent()) { + List bodyRanges = new ArrayList<>(builder.bodyRanges); for (SignalServiceDataMessage.Mention mention : message.getMentions().get()) { - builder.addBodyRanges(BodyRange.newBuilder() - .setStart(mention.getStart()) - .setLength(mention.getLength()) - .setMentionAci(mention.getServiceId().toString())); + bodyRanges.add(new BodyRange.Builder() + .start(mention.getStart()) + .length(mention.getLength()) + .mentionAci(mention.getServiceId().toString()) + .build()); } - builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.MENTIONS_VALUE, builder.getRequiredProtocolVersion())); + builder.bodyRanges(bodyRanges); + builder.requiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.MENTIONS.getValue(), builder.requiredProtocolVersion)); } if (message.getSticker().isPresent()) { - DataMessage.Sticker.Builder stickerBuilder = DataMessage.Sticker.newBuilder(); + DataMessage.Sticker.Builder stickerBuilder = new DataMessage.Sticker.Builder(); - stickerBuilder.setPackId(ByteString.copyFrom(message.getSticker().get().getPackId())); - stickerBuilder.setPackKey(ByteString.copyFrom(message.getSticker().get().getPackKey())); - stickerBuilder.setStickerId(message.getSticker().get().getStickerId()); + stickerBuilder.packId(ByteString.of(message.getSticker().get().getPackId())); + stickerBuilder.packKey(ByteString.of(message.getSticker().get().getPackKey())); + stickerBuilder.stickerId(message.getSticker().get().getStickerId()); if (message.getSticker().get().getEmoji() != null) { - stickerBuilder.setEmoji(message.getSticker().get().getEmoji()); + stickerBuilder.emoji(message.getSticker().get().getEmoji()); } if (message.getSticker().get().getAttachment().isStream()) { - stickerBuilder.setData(createAttachmentPointer(message.getSticker().get().getAttachment().asStream())); + stickerBuilder.data_(createAttachmentPointer(message.getSticker().get().getAttachment().asStream())); } else { - stickerBuilder.setData(createAttachmentPointer(message.getSticker().get().getAttachment().asPointer())); + stickerBuilder.data_(createAttachmentPointer(message.getSticker().get().getAttachment().asPointer())); } - builder.setSticker(stickerBuilder.build()); + builder.sticker(stickerBuilder.build()); } if (message.isViewOnce()) { - builder.setIsViewOnce(message.isViewOnce()); - builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.VIEW_ONCE_VIDEO_VALUE, builder.getRequiredProtocolVersion())); + builder.isViewOnce(message.isViewOnce()); + builder.requiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.VIEW_ONCE_VIDEO.getValue(), builder.requiredProtocolVersion)); } if (message.getReaction().isPresent()) { - DataMessage.Reaction.Builder reactionBuilder = DataMessage.Reaction.newBuilder() - .setEmoji(message.getReaction().get().getEmoji()) - .setRemove(message.getReaction().get().isRemove()) - .setTargetSentTimestamp(message.getReaction().get().getTargetSentTimestamp()) - .setTargetAuthorAci(message.getReaction().get().getTargetAuthor().toString()); + DataMessage.Reaction.Builder reactionBuilder = new DataMessage.Reaction.Builder() + .emoji(message.getReaction().get().getEmoji()) + .remove(message.getReaction().get().isRemove()) + .targetSentTimestamp(message.getReaction().get().getTargetSentTimestamp()) + .targetAuthorAci(message.getReaction().get().getTargetAuthor().toString()); - builder.setReaction(reactionBuilder.build()); - builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.REACTIONS_VALUE, builder.getRequiredProtocolVersion())); + builder.reaction(reactionBuilder.build()); + builder.requiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.REACTIONS.getValue(), builder.requiredProtocolVersion)); } if (message.getRemoteDelete().isPresent()) { - DataMessage.Delete delete = DataMessage.Delete.newBuilder() - .setTargetSentTimestamp(message.getRemoteDelete().get().getTargetSentTimestamp()) - .build(); - builder.setDelete(delete); + DataMessage.Delete delete = new DataMessage.Delete.Builder() + .targetSentTimestamp(message.getRemoteDelete().get().getTargetSentTimestamp()) + .build(); + builder.delete(delete); } if (message.getGroupCallUpdate().isPresent()) { String eraId = message.getGroupCallUpdate().get().getEraId(); if (eraId != null) { - builder.setGroupCallUpdate(DataMessage.GroupCallUpdate.newBuilder().setEraId(eraId)); + builder.groupCallUpdate(new DataMessage.GroupCallUpdate.Builder().eraId(eraId).build()); } else { - builder.setGroupCallUpdate(DataMessage.GroupCallUpdate.getDefaultInstance()); + builder.groupCallUpdate(new DataMessage.GroupCallUpdate()); } } @@ -1203,55 +1216,59 @@ public class SignalServiceMessageSender { if (payment.getPaymentNotification().isPresent()) { SignalServiceDataMessage.PaymentNotification paymentNotification = payment.getPaymentNotification().get(); - DataMessage.Payment.Notification.MobileCoin.Builder mobileCoinPayment = DataMessage.Payment.Notification.MobileCoin.newBuilder().setReceipt(ByteString.copyFrom(paymentNotification.getReceipt())); - DataMessage.Payment.Notification.Builder paymentBuilder = DataMessage.Payment.Notification.newBuilder() - .setNote(paymentNotification.getNote()) - .setMobileCoin(mobileCoinPayment); + DataMessage.Payment.Notification.MobileCoin.Builder mobileCoinPayment = new DataMessage.Payment.Notification.MobileCoin.Builder().receipt(ByteString.of(paymentNotification.getReceipt())); + DataMessage.Payment.Notification.Builder paymentBuilder = new DataMessage.Payment.Notification.Builder() + .note(paymentNotification.getNote()) + .mobileCoin(mobileCoinPayment.build()); - builder.setPayment(DataMessage.Payment.newBuilder().setNotification(paymentBuilder)); + builder.payment(new DataMessage.Payment.Builder().notification(paymentBuilder.build()).build()); } else if (payment.getPaymentActivation().isPresent()) { - DataMessage.Payment.Activation.Builder activationBuilder = DataMessage.Payment.Activation.newBuilder().setType(payment.getPaymentActivation().get().getType()); - builder.setPayment(DataMessage.Payment.newBuilder().setActivation(activationBuilder)); + DataMessage.Payment.Activation.Builder activationBuilder = new DataMessage.Payment.Activation.Builder().type(payment.getPaymentActivation().get().getType()); + builder.payment(new DataMessage.Payment.Builder().activation(activationBuilder.build()).build()); } - builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.PAYMENTS_VALUE, builder.getRequiredProtocolVersion())); + builder.requiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.PAYMENTS.getValue(), builder.requiredProtocolVersion)); } if (message.getStoryContext().isPresent()) { SignalServiceDataMessage.StoryContext storyContext = message.getStoryContext().get(); - builder.setStoryContext(DataMessage.StoryContext.newBuilder() - .setAuthorAci(storyContext.getAuthorServiceId().toString()) - .setSentTimestamp(storyContext.getSentTimestamp())); + builder.storyContext(new DataMessage.StoryContext.Builder() + .authorAci(storyContext.getAuthorServiceId().toString()) + .sentTimestamp(storyContext.getSentTimestamp()) + .build()); } if (message.getGiftBadge().isPresent()) { SignalServiceDataMessage.GiftBadge giftBadge = message.getGiftBadge().get(); - builder.setGiftBadge(DataMessage.GiftBadge.newBuilder() - .setReceiptCredentialPresentation(ByteString.copyFrom(giftBadge.getReceiptCredentialPresentation().serialize()))); + builder.giftBadge(new DataMessage.GiftBadge.Builder() + .receiptCredentialPresentation(ByteString.of(giftBadge.getReceiptCredentialPresentation().serialize())) + .build()); } if (message.getBodyRanges().isPresent()) { - builder.addAllBodyRanges(message.getBodyRanges().get()); + List bodyRanges = new ArrayList<>(builder.bodyRanges); + bodyRanges.addAll(message.getBodyRanges().get()); + builder.bodyRanges(bodyRanges); } - builder.setTimestamp(message.getTimestamp()); + builder.timestamp(message.getTimestamp()); return builder; } private Preview createPreview(SignalServicePreview preview) throws IOException { - Preview.Builder previewBuilder = Preview.newBuilder() - .setTitle(preview.getTitle()) - .setDescription(preview.getDescription()) - .setDate(preview.getDate()) - .setUrl(preview.getUrl()); + Preview.Builder previewBuilder = new Preview.Builder() + .title(preview.getTitle()) + .description(preview.getDescription()) + .date(preview.getDate()) + .url(preview.getUrl()); if (preview.getImage().isPresent()) { if (preview.getImage().get().isStream()) { - previewBuilder.setImage(createAttachmentPointer(preview.getImage().get().asStream())); + previewBuilder.image(createAttachmentPointer(preview.getImage().get().asStream())); } else { - previewBuilder.setImage(createAttachmentPointer(preview.getImage().get().asPointer())); + previewBuilder.image(createAttachmentPointer(preview.getImage().get().asPointer())); } } @@ -1259,96 +1276,96 @@ public class SignalServiceMessageSender { } private Content createCallContent(SignalServiceCallMessage callMessage) { - Content.Builder container = Content.newBuilder(); - CallMessage.Builder builder = CallMessage.newBuilder(); + Content.Builder container = new Content.Builder(); + CallMessage.Builder builder = new CallMessage.Builder(); if (callMessage.getOfferMessage().isPresent()) { OfferMessage offer = callMessage.getOfferMessage().get(); - CallMessage.Offer.Builder offerBuilder = CallMessage.Offer.newBuilder() - .setId(offer.getId()) - .setType(offer.getType().getProtoType()); + CallMessage.Offer.Builder offerBuilder = new CallMessage.Offer.Builder() + .id(offer.getId()) + .type(offer.getType().getProtoType()); if (offer.getOpaque() != null) { - offerBuilder.setOpaque(ByteString.copyFrom(offer.getOpaque())); + offerBuilder.opaque(ByteString.of(offer.getOpaque())); } if (offer.getSdp() != null) { - offerBuilder.setSdp(offer.getSdp()); + offerBuilder.sdp(offer.getSdp()); } - builder.setOffer(offerBuilder); + builder.offer(offerBuilder.build()); } else if (callMessage.getAnswerMessage().isPresent()) { AnswerMessage answer = callMessage.getAnswerMessage().get(); - CallMessage.Answer.Builder answerBuilder = CallMessage.Answer.newBuilder() - .setId(answer.getId()); + CallMessage.Answer.Builder answerBuilder = new CallMessage.Answer.Builder() + .id(answer.getId()); if (answer.getOpaque() != null) { - answerBuilder.setOpaque(ByteString.copyFrom(answer.getOpaque())); + answerBuilder.opaque(ByteString.of(answer.getOpaque())); } if (answer.getSdp() != null) { - answerBuilder.setSdp(answer.getSdp()); + answerBuilder.sdp(answer.getSdp()); } - builder.setAnswer(answerBuilder); + builder.answer(answerBuilder.build()); } else if (callMessage.getIceUpdateMessages().isPresent()) { List updates = callMessage.getIceUpdateMessages().get(); - + List iceUpdates = new ArrayList<>(updates.size()); for (IceUpdateMessage update : updates) { - CallMessage.IceUpdate.Builder iceBuilder = CallMessage.IceUpdate.newBuilder() - .setId(update.getId()) - .setMid("audio") - .setLine(0); + CallMessage.IceUpdate.Builder iceBuilder = new CallMessage.IceUpdate.Builder() + .id(update.getId()) + .mid("audio") + .line(0); if (update.getOpaque() != null) { - iceBuilder.setOpaque(ByteString.copyFrom(update.getOpaque())); + iceBuilder.opaque(ByteString.of(update.getOpaque())); } if (update.getSdp() != null) { - iceBuilder.setSdp(update.getSdp()); + iceBuilder.sdp(update.getSdp()); } - builder.addIceUpdate(iceBuilder); + iceUpdates.add(iceBuilder.build()); } + builder.iceUpdate(iceUpdates); } else if (callMessage.getHangupMessage().isPresent()) { CallMessage.Hangup.Type protoType = callMessage.getHangupMessage().get().getType().getProtoType(); - CallMessage.Hangup.Builder builderForHangup = CallMessage.Hangup.newBuilder() - .setType(protoType) - .setId(callMessage.getHangupMessage().get().getId()); + CallMessage.Hangup.Builder builderForHangup = new CallMessage.Hangup.Builder() + .type(protoType) + .id(callMessage.getHangupMessage().get().getId()); if (protoType != CallMessage.Hangup.Type.HANGUP_NORMAL) { - builderForHangup.setDeviceId(callMessage.getHangupMessage().get().getDeviceId()); + builderForHangup.deviceId(callMessage.getHangupMessage().get().getDeviceId()); } - builder.setHangup(builderForHangup); + builder.hangup(builderForHangup.build()); } else if (callMessage.getBusyMessage().isPresent()) { - builder.setBusy(CallMessage.Busy.newBuilder().setId(callMessage.getBusyMessage().get().getId())); + builder.busy(new CallMessage.Busy.Builder().id(callMessage.getBusyMessage().get().getId()).build()); } else if (callMessage.getOpaqueMessage().isPresent()) { OpaqueMessage opaqueMessage = callMessage.getOpaqueMessage().get(); - ByteString data = ByteString.copyFrom(opaqueMessage.getOpaque()); + ByteString data = ByteString.of(opaqueMessage.getOpaque()); CallMessage.Opaque.Urgency urgency = opaqueMessage.getUrgency().toProto(); - builder.setOpaque(CallMessage.Opaque.newBuilder().setData(data).setUrgency(urgency)); + builder.opaque(new CallMessage.Opaque.Builder().data_(data).urgency(urgency).build()); } - builder.setMultiRing(callMessage.isMultiRing()); - if (callMessage.getDestinationDeviceId().isPresent()) { - builder.setDestinationDeviceId(callMessage.getDestinationDeviceId().get()); + builder.destinationDeviceId(callMessage.getDestinationDeviceId().get()); } - container.setCallMessage(builder); + container.callMessage(builder.build()); return container.build(); } private Content createMultiDeviceContactsContent(SignalServiceAttachmentStream contacts, boolean complete) throws IOException { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder builder = createSyncMessageBuilder(); - builder.setContacts(SyncMessage.Contacts.newBuilder() - .setBlob(createAttachmentPointer(contacts)) - .setComplete(complete)); + builder.contacts(new SyncMessage.Contacts.Builder() + .blob(createAttachmentPointer(contacts)) + .complete(complete) + .build()); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private Content createMultiDeviceSentTranscriptContent(SentTranscriptMessage transcript, boolean unidentifiedAccess) throws IOException { @@ -1370,309 +1387,316 @@ public class SignalServiceMessageSender { boolean isRecipientUpdate, Set storyMessageRecipients) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - SyncMessage.Sent.Builder sentMessage = SyncMessage.Sent.newBuilder(); - DataMessage dataMessage = content != null && content.hasDataMessage() ? content.getDataMessage() : null; - StoryMessage storyMessage = content != null && content.hasStoryMessage() ? content.getStoryMessage() : null; - EditMessage editMessage = content != null && content.hasEditMessage() ? content.getEditMessage() : null; + SyncMessage.Sent.Builder sentMessage = new SyncMessage.Sent.Builder(); + DataMessage dataMessage = content != null && content.dataMessage != null ? content.dataMessage : null; + StoryMessage storyMessage = content != null && content.storyMessage != null ? content.storyMessage : null; + EditMessage editMessage = content != null && content.editMessage != null ? content.editMessage : null; - sentMessage.setTimestamp(timestamp); + sentMessage.timestamp(timestamp); + List unidentifiedDeliveryStatuses = new ArrayList<>(sendMessageResults.size()); for (SendMessageResult result : sendMessageResults) { if (result.getSuccess() != null) { - sentMessage.addUnidentifiedStatus(SyncMessage.Sent.UnidentifiedDeliveryStatus.newBuilder() - .setDestinationServiceId(result.getAddress().getServiceId().toString()) - .setUnidentified(result.getSuccess().isUnidentified()) - .build()); - + unidentifiedDeliveryStatuses.add(new SyncMessage.Sent.UnidentifiedDeliveryStatus.Builder() + .destinationServiceId(result.getAddress().getServiceId().toString()) + .unidentified(result.getSuccess().isUnidentified()) + .build()); } } + sentMessage.unidentifiedStatus(unidentifiedDeliveryStatuses); if (recipient.isPresent()) { - sentMessage.setDestinationServiceId(recipient.get().getServiceId().toString()); + sentMessage.destinationServiceId(recipient.get().getServiceId().toString()); if (recipient.get().getNumber().isPresent()) { - sentMessage.setDestinationE164(recipient.get().getNumber().get()); + sentMessage.destinationE164(recipient.get().getNumber().get()); } } if (dataMessage != null) { - sentMessage.setMessage(dataMessage); - if (dataMessage.getExpireTimer() > 0) { - sentMessage.setExpirationStartTimestamp(System.currentTimeMillis()); + sentMessage.message(dataMessage); + if (dataMessage.expireTimer != null && dataMessage.expireTimer > 0) { + sentMessage.expirationStartTimestamp(System.currentTimeMillis()); } - if (dataMessage.getIsViewOnce()) { - dataMessage = dataMessage.toBuilder().clearAttachments().build(); - sentMessage.setMessage(dataMessage); + if (dataMessage.isViewOnce != null && dataMessage.isViewOnce) { + dataMessage = dataMessage.newBuilder().attachments(Collections.emptyList()).build(); + sentMessage.message(dataMessage); } } if (storyMessage != null) { - sentMessage.setStoryMessage(storyMessage); + sentMessage.storyMessage(storyMessage); } if (editMessage != null) { - sentMessage.setEditMessage(editMessage); + sentMessage.editMessage(editMessage); } - sentMessage.addAllStoryMessageRecipients(storyMessageRecipients.stream() - .map(this::createStoryMessageRecipient) - .collect(Collectors.toSet())); + Set storyMessageRecipientsSet = storyMessageRecipients.stream() + .map(this::createStoryMessageRecipient) + .collect(Collectors.toSet()); + sentMessage.storyMessageRecipients(new ArrayList<>(storyMessageRecipientsSet)); - sentMessage.setIsRecipientUpdate(isRecipientUpdate); + sentMessage.isRecipientUpdate(isRecipientUpdate); - return container.setSyncMessage(syncMessage.setSent(sentMessage)).build(); + return container.syncMessage(syncMessage.sent(sentMessage.build()).build()).build(); } private SyncMessage.Sent.StoryMessageRecipient createStoryMessageRecipient(SignalServiceStoryMessageRecipient storyMessageRecipient) { - return SyncMessage.Sent.StoryMessageRecipient.newBuilder() - .addAllDistributionListIds(storyMessageRecipient.getDistributionListIds()) - .setDestinationServiceId(storyMessageRecipient.getSignalServiceAddress().getIdentifier()) - .setIsAllowedToReply(storyMessageRecipient.isAllowedToReply()) - .build(); + return new SyncMessage.Sent.StoryMessageRecipient.Builder() + .distributionListIds(storyMessageRecipient.getDistributionListIds()) + .destinationServiceId(storyMessageRecipient.getSignalServiceAddress().getIdentifier()) + .isAllowedToReply(storyMessageRecipient.isAllowedToReply()) + .build(); } private Content createMultiDeviceReadContent(List readMessages) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder builder = createSyncMessageBuilder(); - for (ReadMessage readMessage : readMessages) { - builder.addRead(SyncMessage.Read.newBuilder() - .setTimestamp(readMessage.getTimestamp()) - .setSenderAci(readMessage.getSender().toString())); - } + builder.read( + readMessages.stream() + .map(readMessage -> new SyncMessage.Read.Builder() + .timestamp(readMessage.getTimestamp()) + .senderAci(readMessage.getSender().toString()) + .build()) + .collect(Collectors.toList()) + ); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private Content createMultiDeviceViewedContent(List readMessages) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder builder = createSyncMessageBuilder(); - for (ViewedMessage readMessage : readMessages) { - builder.addViewed(SyncMessage.Viewed.newBuilder() - .setTimestamp(readMessage.getTimestamp()) - .setSenderAci(readMessage.getSender().toString())); - } + builder.viewed( + readMessages.stream() + .map(readMessage -> new SyncMessage.Viewed.Builder() + .timestamp(readMessage.getTimestamp()) + .senderAci(readMessage.getSender().toString()) + .build()) + .collect(Collectors.toList()) + ); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private Content createMultiDeviceViewOnceOpenContent(ViewOnceOpenMessage readMessage) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder builder = createSyncMessageBuilder(); - builder.setViewOnceOpen(SyncMessage.ViewOnceOpen.newBuilder() - .setTimestamp(readMessage.getTimestamp()) - .setSenderAci(readMessage.getSender().toString())); + builder.viewOnceOpen(new SyncMessage.ViewOnceOpen.Builder() + .timestamp(readMessage.getTimestamp()) + .senderAci(readMessage.getSender().toString()) + .build()); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private Content createMultiDeviceBlockedContent(BlockedListMessage blocked) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - SyncMessage.Blocked.Builder blockedMessage = SyncMessage.Blocked.newBuilder(); + SyncMessage.Blocked.Builder blockedMessage = new SyncMessage.Blocked.Builder(); - for (SignalServiceAddress address : blocked.getAddresses()) { - blockedMessage.addAcis(address.getServiceId().toString()); - if (address.getNumber().isPresent()) { - blockedMessage.addNumbers(address.getNumber().get()); - } - } + blockedMessage.acis(blocked.getAddresses().stream().map(a -> a.getServiceId().toString()).collect(Collectors.toList())); + blockedMessage.numbers(blocked.getAddresses().stream().filter(a -> a.getNumber().isPresent()).map(a -> a.getNumber().get()).collect(Collectors.toList())); + blockedMessage.groupIds(blocked.getGroupIds().stream().map(ByteString::of).collect(Collectors.toList())); - for (byte[] groupId : blocked.getGroupIds()) { - blockedMessage.addGroupIds(ByteString.copyFrom(groupId)); - } - - return container.setSyncMessage(syncMessage.setBlocked(blockedMessage)).build(); + return container.syncMessage(syncMessage.blocked(blockedMessage.build()).build()).build(); } private Content createMultiDeviceConfigurationContent(ConfigurationMessage configuration) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - SyncMessage.Configuration.Builder configurationMessage = SyncMessage.Configuration.newBuilder(); + SyncMessage.Configuration.Builder configurationMessage = new SyncMessage.Configuration.Builder(); if (configuration.getReadReceipts().isPresent()) { - configurationMessage.setReadReceipts(configuration.getReadReceipts().get()); + configurationMessage.readReceipts(configuration.getReadReceipts().get()); } if (configuration.getUnidentifiedDeliveryIndicators().isPresent()) { - configurationMessage.setUnidentifiedDeliveryIndicators(configuration.getUnidentifiedDeliveryIndicators().get()); + configurationMessage.unidentifiedDeliveryIndicators(configuration.getUnidentifiedDeliveryIndicators().get()); } if (configuration.getTypingIndicators().isPresent()) { - configurationMessage.setTypingIndicators(configuration.getTypingIndicators().get()); + configurationMessage.typingIndicators(configuration.getTypingIndicators().get()); } if (configuration.getLinkPreviews().isPresent()) { - configurationMessage.setLinkPreviews(configuration.getLinkPreviews().get()); + configurationMessage.linkPreviews(configuration.getLinkPreviews().get()); } - configurationMessage.setProvisioningVersion(ProvisioningVersion.CURRENT.getValue()); + configurationMessage.provisioningVersion(ProvisioningVersion.CURRENT.getValue()); - return container.setSyncMessage(syncMessage.setConfiguration(configurationMessage)).build(); + return container.syncMessage(syncMessage.configuration(configurationMessage.build()).build()).build(); } private Content createMultiDeviceStickerPackOperationContent(List stickerPackOperations) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); + List stickerPackOperationProtos = new ArrayList<>(stickerPackOperations.size()); for (StickerPackOperationMessage stickerPackOperation : stickerPackOperations) { - SyncMessage.StickerPackOperation.Builder builder = SyncMessage.StickerPackOperation.newBuilder(); + SyncMessage.StickerPackOperation.Builder builder = new SyncMessage.StickerPackOperation.Builder(); if (stickerPackOperation.getPackId().isPresent()) { - builder.setPackId(ByteString.copyFrom(stickerPackOperation.getPackId().get())); + builder.packId(ByteString.of(stickerPackOperation.getPackId().get())); } if (stickerPackOperation.getPackKey().isPresent()) { - builder.setPackKey(ByteString.copyFrom(stickerPackOperation.getPackKey().get())); + builder.packKey(ByteString.of(stickerPackOperation.getPackKey().get())); } if (stickerPackOperation.getType().isPresent()) { switch (stickerPackOperation.getType().get()) { - case INSTALL: builder.setType(SyncMessage.StickerPackOperation.Type.INSTALL); break; - case REMOVE: builder.setType(SyncMessage.StickerPackOperation.Type.REMOVE); break; + case INSTALL: + builder.type(SyncMessage.StickerPackOperation.Type.INSTALL); + break; + case REMOVE: + builder.type(SyncMessage.StickerPackOperation.Type.REMOVE); + break; } } - syncMessage.addStickerPackOperation(builder); + stickerPackOperationProtos.add(builder.build()); } - return container.setSyncMessage(syncMessage).build(); + return container.syncMessage(syncMessage.stickerPackOperation(stickerPackOperationProtos).build()).build(); } private Content createMultiDeviceFetchTypeContent(SignalServiceSyncMessage.FetchType fetchType) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - SyncMessage.FetchLatest.Builder fetchMessage = SyncMessage.FetchLatest.newBuilder(); + SyncMessage.FetchLatest.Builder fetchMessage = new SyncMessage.FetchLatest.Builder(); switch (fetchType) { case LOCAL_PROFILE: - fetchMessage.setType(SyncMessage.FetchLatest.Type.LOCAL_PROFILE); + fetchMessage.type(SyncMessage.FetchLatest.Type.LOCAL_PROFILE); break; case STORAGE_MANIFEST: - fetchMessage.setType(SyncMessage.FetchLatest.Type.STORAGE_MANIFEST); + fetchMessage.type(SyncMessage.FetchLatest.Type.STORAGE_MANIFEST); break; case SUBSCRIPTION_STATUS: - fetchMessage.setType(SyncMessage.FetchLatest.Type.SUBSCRIPTION_STATUS); + fetchMessage.type(SyncMessage.FetchLatest.Type.SUBSCRIPTION_STATUS); break; default: Log.w(TAG, "Unknown fetch type!"); break; } - return container.setSyncMessage(syncMessage.setFetchLatest(fetchMessage)).build(); + return container.syncMessage(syncMessage.fetchLatest(fetchMessage.build()).build()).build(); } private Content createMultiDeviceMessageRequestResponseContent(MessageRequestResponseMessage message) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - SyncMessage.MessageRequestResponse.Builder responseMessage = SyncMessage.MessageRequestResponse.newBuilder(); + SyncMessage.MessageRequestResponse.Builder responseMessage = new SyncMessage.MessageRequestResponse.Builder(); if (message.getGroupId().isPresent()) { - responseMessage.setGroupId(ByteString.copyFrom(message.getGroupId().get())); + responseMessage.groupId(ByteString.of(message.getGroupId().get())); } if (message.getPerson().isPresent()) { - responseMessage.setThreadAci(message.getPerson().get().toString()); + responseMessage.threadAci(message.getPerson().get().toString()); } switch (message.getType()) { case ACCEPT: - responseMessage.setType(SyncMessage.MessageRequestResponse.Type.ACCEPT); + responseMessage.type(SyncMessage.MessageRequestResponse.Type.ACCEPT); break; case DELETE: - responseMessage.setType(SyncMessage.MessageRequestResponse.Type.DELETE); + responseMessage.type(SyncMessage.MessageRequestResponse.Type.DELETE); break; case BLOCK: - responseMessage.setType(SyncMessage.MessageRequestResponse.Type.BLOCK); + responseMessage.type(SyncMessage.MessageRequestResponse.Type.BLOCK); break; case BLOCK_AND_DELETE: - responseMessage.setType(SyncMessage.MessageRequestResponse.Type.BLOCK_AND_DELETE); + responseMessage.type(SyncMessage.MessageRequestResponse.Type.BLOCK_AND_DELETE); break; default: Log.w(TAG, "Unknown type!"); - responseMessage.setType(SyncMessage.MessageRequestResponse.Type.UNKNOWN); + responseMessage.type(SyncMessage.MessageRequestResponse.Type.UNKNOWN); break; } - syncMessage.setMessageRequestResponse(responseMessage); + syncMessage.messageRequestResponse(responseMessage.build()); - return container.setSyncMessage(syncMessage).build(); + return container.syncMessage(syncMessage.build()).build(); } private Content createMultiDeviceOutgoingPaymentContent(OutgoingPaymentMessage message) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - SyncMessage.OutgoingPayment.Builder paymentMessage = SyncMessage.OutgoingPayment.newBuilder(); + SyncMessage.OutgoingPayment.Builder paymentMessage = new SyncMessage.OutgoingPayment.Builder(); if (message.getRecipient().isPresent()) { - paymentMessage.setRecipientServiceId(message.getRecipient().get().toString()); + paymentMessage.recipientServiceId(message.getRecipient().get().toString()); } if (message.getNote().isPresent()) { - paymentMessage.setNote(message.getNote().get()); + paymentMessage.note(message.getNote().get()); } try { - SyncMessage.OutgoingPayment.MobileCoin.Builder mobileCoinBuilder = SyncMessage.OutgoingPayment.MobileCoin.newBuilder(); + SyncMessage.OutgoingPayment.MobileCoin.Builder mobileCoinBuilder = new SyncMessage.OutgoingPayment.MobileCoin.Builder(); if (message.getAddress().isPresent()) { - mobileCoinBuilder.setRecipientAddress(ByteString.copyFrom(message.getAddress().get())); + mobileCoinBuilder.recipientAddress(ByteString.of(message.getAddress().get())); } - mobileCoinBuilder.setAmountPicoMob(Uint64Util.bigIntegerToUInt64(message.getAmount().toPicoMobBigInteger())) - .setFeePicoMob(Uint64Util.bigIntegerToUInt64(message.getFee().toPicoMobBigInteger())) - .setReceipt(message.getReceipt()) - .setLedgerBlockTimestamp(message.getBlockTimestamp()) - .setLedgerBlockIndex(message.getBlockIndex()) - .addAllOutputPublicKeys(message.getPublicKeys()) - .addAllSpentKeyImages(message.getKeyImages()); + mobileCoinBuilder.amountPicoMob(Uint64Util.bigIntegerToUInt64(message.getAmount().toPicoMobBigInteger())) + .feePicoMob(Uint64Util.bigIntegerToUInt64(message.getFee().toPicoMobBigInteger())) + .receipt(message.getReceipt()) + .ledgerBlockTimestamp(message.getBlockTimestamp()) + .ledgerBlockIndex(message.getBlockIndex()) + .outputPublicKeys(message.getPublicKeys()) + .spentKeyImages(message.getKeyImages()); - paymentMessage.setMobileCoin(mobileCoinBuilder); + paymentMessage.mobileCoin(mobileCoinBuilder.build()); } catch (Uint64RangeException e) { throw new AssertionError(e); } - syncMessage.setOutgoingPayment(paymentMessage); + syncMessage.outgoingPayment(paymentMessage.build()); - return container.setSyncMessage(syncMessage).build(); + return container.syncMessage(syncMessage.build()).build(); } private Content createMultiDeviceSyncKeysContent(KeysMessage keysMessage) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - SyncMessage.Keys.Builder builder = SyncMessage.Keys.newBuilder(); + SyncMessage.Keys.Builder builder = new SyncMessage.Keys.Builder(); if (keysMessage.getStorageService().isPresent()) { - builder.setStorageService(ByteString.copyFrom(keysMessage.getStorageService().get().serialize())); + builder.storageService(ByteString.of(keysMessage.getStorageService().get().serialize())); } else { Log.w(TAG, "Invalid keys message!"); } - return container.setSyncMessage(syncMessage.setKeys(builder)).build(); + return container.syncMessage(syncMessage.keys(builder.build()).build()).build(); } private Content createMultiDeviceVerifiedContent(VerifiedMessage verifiedMessage, byte[] nullMessage) { - Content.Builder container = Content.newBuilder(); + Content.Builder container = new Content.Builder(); SyncMessage.Builder syncMessage = createSyncMessageBuilder(); - Verified.Builder verifiedMessageBuilder = Verified.newBuilder(); + Verified.Builder verifiedMessageBuilder = new Verified.Builder(); - verifiedMessageBuilder.setNullMessage(ByteString.copyFrom(nullMessage)); - verifiedMessageBuilder.setIdentityKey(ByteString.copyFrom(verifiedMessage.getIdentityKey().serialize())); - verifiedMessageBuilder.setDestinationAci(verifiedMessage.getDestination().getServiceId().toString()); + verifiedMessageBuilder.nullMessage(ByteString.of(nullMessage)); + verifiedMessageBuilder.identityKey(ByteString.of(verifiedMessage.getIdentityKey().serialize())); + verifiedMessageBuilder.destinationAci(verifiedMessage.getDestination().getServiceId().toString()); - switch(verifiedMessage.getVerified()) { - case DEFAULT: verifiedMessageBuilder.setState(Verified.State.DEFAULT); break; - case VERIFIED: verifiedMessageBuilder.setState(Verified.State.VERIFIED); break; - case UNVERIFIED: verifiedMessageBuilder.setState(Verified.State.UNVERIFIED); break; + switch (verifiedMessage.getVerified()) { + case DEFAULT: verifiedMessageBuilder.state(Verified.State.DEFAULT); break; + case VERIFIED: verifiedMessageBuilder.state(Verified.State.VERIFIED); break; + case UNVERIFIED: verifiedMessageBuilder.state(Verified.State.UNVERIFIED); break; default: throw new AssertionError("Unknown: " + verifiedMessage.getVerified()); } - syncMessage.setVerified(verifiedMessageBuilder); - return container.setSyncMessage(syncMessage).build(); + syncMessage.verified(verifiedMessageBuilder.build()); + return container.syncMessage(syncMessage.build()).build(); } private Content createRequestContent(SyncMessage.Request request) throws IOException { @@ -1680,31 +1704,31 @@ public class SignalServiceMessageSender { throw new IOException("Sync requests should only be sent from a linked device"); } - Content.Builder container = Content.newBuilder(); - SyncMessage.Builder builder = createSyncMessageBuilder().setRequest(request); + Content.Builder container = new Content.Builder(); + SyncMessage.Builder builder = createSyncMessageBuilder().request(request); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private Content createCallEventContent(SyncMessage.CallEvent proto) { - Content.Builder container = Content.newBuilder(); - SyncMessage.Builder builder = createSyncMessageBuilder().setCallEvent(proto); + Content.Builder container = new Content.Builder(); + SyncMessage.Builder builder = createSyncMessageBuilder().callEvent(proto); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private Content createCallLinkUpdateContent(SyncMessage.CallLinkUpdate proto) { - Content.Builder container = Content.newBuilder(); - SyncMessage.Builder builder = createSyncMessageBuilder().setCallLinkUpdate(proto); + Content.Builder container = new Content.Builder(); + SyncMessage.Builder builder = createSyncMessageBuilder().callLinkUpdate(proto); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private Content createCallLogEventContent(SyncMessage.CallLogEvent proto) { - Content.Builder container = Content.newBuilder(); - SyncMessage.Builder builder = createSyncMessageBuilder().setCallLogEvent(proto); + Content.Builder container = new Content.Builder(); + SyncMessage.Builder builder = createSyncMessageBuilder().callLogEvent(proto); - return container.setSyncMessage(builder).build(); + return container.syncMessage(builder.build()).build(); } private SyncMessage.Builder createSyncMessageBuilder() { @@ -1712,21 +1736,20 @@ public class SignalServiceMessageSender { byte[] padding = Util.getRandomLengthBytes(512); random.nextBytes(padding); - SyncMessage.Builder builder = SyncMessage.newBuilder(); - builder.setPadding(ByteString.copyFrom(padding)); + SyncMessage.Builder builder = new SyncMessage.Builder(); + builder.padding(ByteString.of(padding)); return builder; } private static GroupContextV2 createGroupContent(SignalServiceGroupV2 group) { - GroupContextV2.Builder builder = GroupContextV2.newBuilder() - .setMasterKey(ByteString.copyFrom(group.getMasterKey().serialize())) - .setRevision(group.getRevision()); - + GroupContextV2.Builder builder = new GroupContextV2.Builder() + .masterKey(ByteString.of(group.getMasterKey().serialize())) + .revision(group.getRevision()); byte[] signedGroupChange = group.getSignedGroupChange(); if (signedGroupChange != null && signedGroupChange.length <= 2048) { - builder.setGroupChange(ByteString.copyFrom(signedGroupChange)); + builder.groupChange(ByteString.of(signedGroupChange)); } return builder.build(); @@ -1736,90 +1759,94 @@ public class SignalServiceMessageSender { List results = new LinkedList<>(); for (SharedContact contact : contacts) { - DataMessage.Contact.Name.Builder nameBuilder = DataMessage.Contact.Name.newBuilder(); + DataMessage.Contact.Name.Builder nameBuilder = new DataMessage.Contact.Name.Builder(); - if (contact.getName().getFamily().isPresent()) nameBuilder.setFamilyName(contact.getName().getFamily().get()); - if (contact.getName().getGiven().isPresent()) nameBuilder.setGivenName(contact.getName().getGiven().get()); - if (contact.getName().getMiddle().isPresent()) nameBuilder.setMiddleName(contact.getName().getMiddle().get()); - if (contact.getName().getPrefix().isPresent()) nameBuilder.setPrefix(contact.getName().getPrefix().get()); - if (contact.getName().getSuffix().isPresent()) nameBuilder.setSuffix(contact.getName().getSuffix().get()); - if (contact.getName().getDisplay().isPresent()) nameBuilder.setDisplayName(contact.getName().getDisplay().get()); + if (contact.getName().getFamily().isPresent()) nameBuilder.familyName(contact.getName().getFamily().get()); + if (contact.getName().getGiven().isPresent()) nameBuilder.givenName(contact.getName().getGiven().get()); + if (contact.getName().getMiddle().isPresent()) nameBuilder.middleName(contact.getName().getMiddle().get()); + if (contact.getName().getPrefix().isPresent()) nameBuilder.prefix(contact.getName().getPrefix().get()); + if (contact.getName().getSuffix().isPresent()) nameBuilder.suffix(contact.getName().getSuffix().get()); + if (contact.getName().getDisplay().isPresent()) nameBuilder.displayName(contact.getName().getDisplay().get()); - DataMessage.Contact.Builder contactBuilder = DataMessage.Contact.newBuilder() - .setName(nameBuilder); + DataMessage.Contact.Builder contactBuilder = new DataMessage.Contact.Builder().name(nameBuilder.build()); if (contact.getAddress().isPresent()) { + List postalAddresses = new ArrayList<>(contact.getAddress().get().size()); for (SharedContact.PostalAddress address : contact.getAddress().get()) { - DataMessage.Contact.PostalAddress.Builder addressBuilder = DataMessage.Contact.PostalAddress.newBuilder(); + DataMessage.Contact.PostalAddress.Builder addressBuilder = new DataMessage.Contact.PostalAddress.Builder(); switch (address.getType()) { - case HOME: addressBuilder.setType(DataMessage.Contact.PostalAddress.Type.HOME); break; - case WORK: addressBuilder.setType(DataMessage.Contact.PostalAddress.Type.WORK); break; - case CUSTOM: addressBuilder.setType(DataMessage.Contact.PostalAddress.Type.CUSTOM); break; + case HOME: addressBuilder.type(DataMessage.Contact.PostalAddress.Type.HOME); break; + case WORK: addressBuilder.type(DataMessage.Contact.PostalAddress.Type.WORK); break; + case CUSTOM: addressBuilder.type(DataMessage.Contact.PostalAddress.Type.CUSTOM); break; default: throw new AssertionError("Unknown type: " + address.getType()); } - if (address.getCity().isPresent()) addressBuilder.setCity(address.getCity().get()); - if (address.getCountry().isPresent()) addressBuilder.setCountry(address.getCountry().get()); - if (address.getLabel().isPresent()) addressBuilder.setLabel(address.getLabel().get()); - if (address.getNeighborhood().isPresent()) addressBuilder.setNeighborhood(address.getNeighborhood().get()); - if (address.getPobox().isPresent()) addressBuilder.setPobox(address.getPobox().get()); - if (address.getPostcode().isPresent()) addressBuilder.setPostcode(address.getPostcode().get()); - if (address.getRegion().isPresent()) addressBuilder.setRegion(address.getRegion().get()); - if (address.getStreet().isPresent()) addressBuilder.setStreet(address.getStreet().get()); + if (address.getCity().isPresent()) addressBuilder.city(address.getCity().get()); + if (address.getCountry().isPresent()) addressBuilder.country(address.getCountry().get()); + if (address.getLabel().isPresent()) addressBuilder.label(address.getLabel().get()); + if (address.getNeighborhood().isPresent()) addressBuilder.neighborhood(address.getNeighborhood().get()); + if (address.getPobox().isPresent()) addressBuilder.pobox(address.getPobox().get()); + if (address.getPostcode().isPresent()) addressBuilder.postcode(address.getPostcode().get()); + if (address.getRegion().isPresent()) addressBuilder.region(address.getRegion().get()); + if (address.getStreet().isPresent()) addressBuilder.street(address.getStreet().get()); - contactBuilder.addAddress(addressBuilder); + postalAddresses.add(addressBuilder.build()); } + contactBuilder.address(postalAddresses); } if (contact.getEmail().isPresent()) { + List emails = new ArrayList<>(contact.getEmail().get().size()); for (SharedContact.Email email : contact.getEmail().get()) { - DataMessage.Contact.Email.Builder emailBuilder = DataMessage.Contact.Email.newBuilder() - .setValue(email.getValue()); + DataMessage.Contact.Email.Builder emailBuilder = new DataMessage.Contact.Email.Builder().value_(email.getValue()); switch (email.getType()) { - case HOME: emailBuilder.setType(DataMessage.Contact.Email.Type.HOME); break; - case WORK: emailBuilder.setType(DataMessage.Contact.Email.Type.WORK); break; - case MOBILE: emailBuilder.setType(DataMessage.Contact.Email.Type.MOBILE); break; - case CUSTOM: emailBuilder.setType(DataMessage.Contact.Email.Type.CUSTOM); break; + case HOME: emailBuilder.type(DataMessage.Contact.Email.Type.HOME); break; + case WORK: emailBuilder.type(DataMessage.Contact.Email.Type.WORK); break; + case MOBILE: emailBuilder.type(DataMessage.Contact.Email.Type.MOBILE); break; + case CUSTOM: emailBuilder.type(DataMessage.Contact.Email.Type.CUSTOM); break; default: throw new AssertionError("Unknown type: " + email.getType()); } - if (email.getLabel().isPresent()) emailBuilder.setLabel(email.getLabel().get()); + if (email.getLabel().isPresent()) emailBuilder.label(email.getLabel().get()); - contactBuilder.addEmail(emailBuilder); + emails.add(emailBuilder.build()); } + contactBuilder.email(emails); } if (contact.getPhone().isPresent()) { + List phones = new ArrayList<>(contact.getPhone().get().size()); for (SharedContact.Phone phone : contact.getPhone().get()) { - DataMessage.Contact.Phone.Builder phoneBuilder = DataMessage.Contact.Phone.newBuilder() - .setValue(phone.getValue()); + DataMessage.Contact.Phone.Builder phoneBuilder = new DataMessage.Contact.Phone.Builder().value_(phone.getValue()); switch (phone.getType()) { - case HOME: phoneBuilder.setType(DataMessage.Contact.Phone.Type.HOME); break; - case WORK: phoneBuilder.setType(DataMessage.Contact.Phone.Type.WORK); break; - case MOBILE: phoneBuilder.setType(DataMessage.Contact.Phone.Type.MOBILE); break; - case CUSTOM: phoneBuilder.setType(DataMessage.Contact.Phone.Type.CUSTOM); break; + case HOME: phoneBuilder.type(DataMessage.Contact.Phone.Type.HOME); break; + case WORK: phoneBuilder.type(DataMessage.Contact.Phone.Type.WORK); break; + case MOBILE: phoneBuilder.type(DataMessage.Contact.Phone.Type.MOBILE); break; + case CUSTOM: phoneBuilder.type(DataMessage.Contact.Phone.Type.CUSTOM); break; default: throw new AssertionError("Unknown type: " + phone.getType()); } - if (phone.getLabel().isPresent()) phoneBuilder.setLabel(phone.getLabel().get()); + if (phone.getLabel().isPresent()) phoneBuilder.label(phone.getLabel().get()); - contactBuilder.addNumber(phoneBuilder); + phones.add(phoneBuilder.build()); } + contactBuilder.number(phones); } if (contact.getAvatar().isPresent()) { AttachmentPointer pointer = contact.getAvatar().get().getAttachment().isStream() ? createAttachmentPointer(contact.getAvatar().get().getAttachment().asStream()) : createAttachmentPointer(contact.getAvatar().get().getAttachment().asPointer()); - contactBuilder.setAvatar(DataMessage.Contact.Avatar.newBuilder() - .setAvatar(pointer) - .setIsProfile(contact.getAvatar().get().isProfile())); + contactBuilder.avatar(new DataMessage.Contact.Avatar.Builder() + .avatar(pointer) + .isProfile(contact.getAvatar().get().isProfile()) + .build()); } if (contact.getOrganization().isPresent()) { - contactBuilder.setOrganization(contact.getOrganization().get()); + contactBuilder.organization(contact.getOrganization().get()); } results.add(contactBuilder.build()); @@ -1983,10 +2010,10 @@ public class SignalServiceMessageSender { try { OutgoingPushMessageList messages = getEncryptedMessages(recipient, unidentifiedAccess, timestamp, content, online, urgent, story); - if (content.getContent().isPresent() && content.getContent().get().getSyncMessage() != null && content.getContent().get().getSyncMessage().hasSent()) { + if (content.getContent().isPresent() && content.getContent().get().syncMessage != null && content.getContent().get().syncMessage.sent != null) { Log.d(TAG, "[sendMessage][" + timestamp + "] Sending a sent sync message to devices: " + messages.getDevices()); - } else if (content.getContent().isPresent() && content.getContent().get().hasSenderKeyDistributionMessage()) { - Log.d(TAG, "[sendMessage][" + timestamp + "] Sending a SKDM to " + messages.getDestination() + " for devices: " + messages.getDevices() + (content.getContent().get().hasDataMessage() ? " (it's piggy-backing on a DataMessage)" : "")); + } else if (content.getContent().isPresent() && content.getContent().get().senderKeyDistributionMessage != null) { + Log.d(TAG, "[sendMessage][" + timestamp + "] Sending a SKDM to " + messages.getDestination() + " for devices: " + messages.getDevices() + (content.getContent().get().dataMessage != null ? " (it's piggy-backing on a DataMessage)" : "")); } if (cancelationSignal != null && cancelationSignal.isCanceled()) { @@ -2162,7 +2189,7 @@ public class SignalServiceMessageSender { byte[] ciphertext; try { - ciphertext = cipher.encryptForGroup(distributionId, targetInfo.destinations, senderCertificate, content.toByteArray(), contentHint, groupId); + ciphertext = cipher.encryptForGroup(distributionId, targetInfo.destinations, senderCertificate, content.encode(), contentHint, groupId); } catch (org.signal.libsignal.protocol.UntrustedIdentityException e) { throw new UntrustedIdentityException("Untrusted during group encrypt", e.getName(), e.getUntrustedIdentity()); } @@ -2298,56 +2325,56 @@ public class SignalServiceMessageSender { } private TextAttachment createTextAttachment(SignalServiceTextAttachment attachment) throws IOException { - TextAttachment.Builder builder = TextAttachment.newBuilder(); + TextAttachment.Builder builder = new TextAttachment.Builder(); if (attachment.getStyle().isPresent()) { switch (attachment.getStyle().get()) { case DEFAULT: - builder.setTextStyle(TextAttachment.Style.DEFAULT); + builder.textStyle(TextAttachment.Style.DEFAULT); break; case REGULAR: - builder.setTextStyle(TextAttachment.Style.REGULAR); + builder.textStyle(TextAttachment.Style.REGULAR); break; case BOLD: - builder.setTextStyle(TextAttachment.Style.BOLD); + builder.textStyle(TextAttachment.Style.BOLD); break; case SERIF: - builder.setTextStyle(TextAttachment.Style.SERIF); + builder.textStyle(TextAttachment.Style.SERIF); break; case SCRIPT: - builder.setTextStyle(TextAttachment.Style.SCRIPT); + builder.textStyle(TextAttachment.Style.SCRIPT); break; case CONDENSED: - builder.setTextStyle(TextAttachment.Style.CONDENSED); + builder.textStyle(TextAttachment.Style.CONDENSED); break; default: throw new AssertionError("Unknown type: " + attachment.getStyle().get()); } } - TextAttachment.Gradient.Builder gradientBuilder = TextAttachment.Gradient.newBuilder(); + TextAttachment.Gradient.Builder gradientBuilder = new TextAttachment.Gradient.Builder(); if (attachment.getBackgroundGradient().isPresent()) { SignalServiceTextAttachment.Gradient gradient = attachment.getBackgroundGradient().get(); - if (gradient.getAngle().isPresent()) gradientBuilder.setAngle(gradient.getAngle().get()); + if (gradient.getAngle().isPresent()) gradientBuilder.angle(gradient.getAngle().get()); if (!gradient.getColors().isEmpty()) { - gradientBuilder.setStartColor(gradient.getColors().get(0)); - gradientBuilder.setEndColor(gradient.getColors().get(gradient.getColors().size() - 1)); + gradientBuilder.startColor(gradient.getColors().get(0)); + gradientBuilder.endColor(gradient.getColors().get(gradient.getColors().size() - 1)); } - gradientBuilder.addAllColors(gradient.getColors()); - gradientBuilder.addAllPositions(gradient.getPositions()); + gradientBuilder.colors = gradient.getColors(); + gradientBuilder.positions = gradient.getPositions(); - builder.setGradient(gradientBuilder.build()); + builder.gradient(gradientBuilder.build()); } - if (attachment.getText().isPresent()) builder.setText(attachment.getText().get()); - if (attachment.getTextForegroundColor().isPresent()) builder.setTextForegroundColor(attachment.getTextForegroundColor().get()); - if (attachment.getTextBackgroundColor().isPresent()) builder.setTextBackgroundColor(attachment.getTextBackgroundColor().get()); - if (attachment.getPreview().isPresent()) builder.setPreview(createPreview(attachment.getPreview().get())); - if (attachment.getBackgroundColor().isPresent()) builder.setColor(attachment.getBackgroundColor().get()); + if (attachment.getText().isPresent()) builder.text(attachment.getText().get()); + if (attachment.getTextForegroundColor().isPresent()) builder.textForegroundColor(attachment.getTextForegroundColor().get()); + if (attachment.getTextBackgroundColor().isPresent()) builder.textBackgroundColor(attachment.getTextBackgroundColor().get()); + if (attachment.getPreview().isPresent()) builder.preview(createPreview(attachment.getPreview().get())); + if (attachment.getBackgroundColor().isPresent()) builder.color(attachment.getBackgroundColor().get()); return builder.build(); } @@ -2527,7 +2554,7 @@ public class SignalServiceMessageSender { } private Content enforceMaxContentSize(Content content) { - int size = content.toByteArray().length; + int size = content.encode().length; if (maxEnvelopeSize > 0 && size > maxEnvelopeSize) { throw new ContentTooLargeException(size); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalWebSocket.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalWebSocket.java index 44c444e5e2..0c7dccce8f 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalWebSocket.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalWebSocket.java @@ -6,7 +6,7 @@ import org.whispersystems.signalservice.api.messages.EnvelopeResponse; import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState; import org.whispersystems.signalservice.api.websocket.WebSocketFactory; import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.Envelope; import org.whispersystems.signalservice.internal.websocket.WebSocketConnection; import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage; import org.whispersystems.signalservice.internal.websocket.WebSocketResponseMessage; @@ -312,7 +312,7 @@ public final class SignalWebSocket { } } - SignalServiceProtos.Envelope envelope = SignalServiceProtos.Envelope.parseFrom(request.body.toByteArray()); + Envelope envelope = Envelope.ADAPTER.decode(request.body.toByteArray()); return new EnvelopeResponse(envelope, timestamp, request); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java index af84564696..aeea9fb0a2 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeContent.java @@ -9,10 +9,10 @@ import org.signal.libsignal.protocol.UntrustedIdentityException; import org.signal.libsignal.protocol.message.CiphertextMessage; import org.signal.libsignal.protocol.message.DecryptionErrorMessage; import org.signal.libsignal.protocol.message.PlaintextContent; +import org.whispersystems.signalservice.internal.push.Content; +import org.whispersystems.signalservice.internal.push.Envelope.Type; import org.whispersystems.signalservice.internal.push.OutgoingPushMessage; import org.whispersystems.signalservice.internal.push.PushTransportDetails; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope.Type; import org.whispersystems.util.Base64; import java.util.Optional; @@ -81,7 +81,7 @@ public interface EnvelopeContent { throws UntrustedIdentityException, InvalidKeyException, NoSessionException { PushTransportDetails transportDetails = new PushTransportDetails(); - CiphertextMessage message = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(content.toByteArray())); + CiphertextMessage message = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(content.encode())); UnidentifiedSenderMessageContent messageContent = new UnidentifiedSenderMessageContent(message, senderCertificate, contentHint.getType(), @@ -91,21 +91,21 @@ public interface EnvelopeContent { String body = Base64.encodeBytes(ciphertext); int remoteRegistrationId = sealedSessionCipher.getRemoteRegistrationId(destination); - return new OutgoingPushMessage(Type.UNIDENTIFIED_SENDER_VALUE, destination.getDeviceId(), remoteRegistrationId, body); + return new OutgoingPushMessage(Type.UNIDENTIFIED_SENDER.getValue(), destination.getDeviceId(), remoteRegistrationId, body); } @Override public OutgoingPushMessage processUnsealedSender(SignalSessionCipher sessionCipher, SignalProtocolAddress destination) throws UntrustedIdentityException, NoSessionException { PushTransportDetails transportDetails = new PushTransportDetails(); - CiphertextMessage message = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(content.toByteArray())); + CiphertextMessage message = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(content.encode())); int remoteRegistrationId = sessionCipher.getRemoteRegistrationId(); String body = Base64.encodeBytes(message.serialize()); int type; switch (message.getType()) { - case CiphertextMessage.PREKEY_TYPE: type = Type.PREKEY_BUNDLE_VALUE; break; - case CiphertextMessage.WHISPER_TYPE: type = Type.CIPHERTEXT_VALUE; break; + case CiphertextMessage.PREKEY_TYPE: type = Type.PREKEY_BUNDLE.getValue(); break; + case CiphertextMessage.WHISPER_TYPE: type = Type.CIPHERTEXT.getValue(); break; default: throw new AssertionError("Bad type: " + message.getType()); } @@ -114,7 +114,7 @@ public interface EnvelopeContent { @Override public int size() { - return content.getSerializedSize(); + return Content.ADAPTER.encodedSize(content); } @Override @@ -149,7 +149,7 @@ public interface EnvelopeContent { String body = Base64.encodeBytes(ciphertext); int remoteRegistrationId = sealedSessionCipher.getRemoteRegistrationId(destination); - return new OutgoingPushMessage(Type.UNIDENTIFIED_SENDER_VALUE, destination.getDeviceId(), remoteRegistrationId, body); + return new OutgoingPushMessage(Type.UNIDENTIFIED_SENDER.getValue(), destination.getDeviceId(), remoteRegistrationId, body); } @Override @@ -157,7 +157,7 @@ public interface EnvelopeContent { String body = Base64.encodeBytes(plaintextContent.serialize()); int remoteRegistrationId = sessionCipher.getRemoteRegistrationId(); - return new OutgoingPushMessage(Type.PLAINTEXT_CONTENT_VALUE, destination.getDeviceId(), remoteRegistrationId, body); + return new OutgoingPushMessage(Type.PLAINTEXT_CONTENT.getValue(), destination.getDeviceId(), remoteRegistrationId, body); } @Override diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java index c91434c0b0..97e85e96c2 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java @@ -6,8 +6,6 @@ package org.whispersystems.signalservice.api.crypto; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.libsignal.metadata.InvalidMetadataMessageException; import org.signal.libsignal.metadata.InvalidMetadataVersionException; import org.signal.libsignal.metadata.ProtocolDuplicateMessageException; @@ -50,11 +48,12 @@ import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import org.whispersystems.signalservice.internal.push.Content; +import org.whispersystems.signalservice.internal.push.Envelope; import org.whispersystems.signalservice.internal.push.OutgoingPushMessage; import org.whispersystems.signalservice.internal.push.PushTransportDetails; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope; +import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -136,9 +135,9 @@ public class SignalServiceCipher { SelfSendException, InvalidMessageStructureException { try { - if (envelope.hasContent()) { - Plaintext plaintext = decryptInternal(envelope, serverDeliveredTimestamp); - SignalServiceProtos.Content content = SignalServiceProtos.Content.parseFrom(plaintext.getData()); + if (envelope.content != null) { + Plaintext plaintext = decryptInternal(envelope, serverDeliveredTimestamp); + Content content = Content.ADAPTER.decode(plaintext.getData()); return new SignalServiceCipherResult( content, @@ -154,7 +153,7 @@ public class SignalServiceCipher { } else { return null; } - } catch (InvalidProtocolBufferException e) { + } catch (IOException | IllegalArgumentException e) { throw new InvalidMetadataMessageException(e); } } @@ -172,36 +171,36 @@ public class SignalServiceCipher { byte[] paddedMessage; SignalServiceMetadata metadata; - if (!envelope.hasSourceServiceId() && envelope.getType().getNumber() != Envelope.Type.UNIDENTIFIED_SENDER_VALUE) { + if (envelope.sourceServiceId == null && envelope.type != Envelope.Type.UNIDENTIFIED_SENDER) { throw new InvalidMessageStructureException("Non-UD envelope is missing a UUID!"); } - if (envelope.getType().getNumber() == Envelope.Type.PREKEY_BUNDLE_VALUE) { - SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceServiceId(), envelope.getSourceDevice()); + if (envelope.type == Envelope.Type.PREKEY_BUNDLE) { + SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.sourceServiceId, envelope.sourceDevice); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress)); - paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(envelope.getContent().toByteArray())); - metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerTimestamp(), serverDeliveredTimestamp, false, envelope.getServerGuid(), Optional.empty(), envelope.getDestinationServiceId()); + paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(envelope.content.toByteArray())); + metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, envelope.serverGuid, Optional.empty(), envelope.destinationServiceId); signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress)); - } else if (envelope.getType().getNumber() == Envelope.Type.CIPHERTEXT_VALUE) { - SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceServiceId(), envelope.getSourceDevice()); + } else if (envelope.type == Envelope.Type.CIPHERTEXT) { + SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.sourceServiceId, envelope.sourceDevice); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress)); - paddedMessage = sessionCipher.decrypt(new SignalMessage(envelope.getContent().toByteArray())); - metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerTimestamp(), serverDeliveredTimestamp, false, envelope.getServerGuid(), Optional.empty(), envelope.getDestinationServiceId()); - } else if (envelope.getType().getNumber() == Envelope.Type.PLAINTEXT_CONTENT_VALUE) { - paddedMessage = new PlaintextContent(envelope.getContent().toByteArray()).getBody(); - metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerTimestamp(), serverDeliveredTimestamp, false, envelope.getServerGuid(), Optional.empty(), envelope.getDestinationServiceId()); - } else if (envelope.getType().getNumber() == Envelope.Type.UNIDENTIFIED_SENDER_VALUE) { + paddedMessage = sessionCipher.decrypt(new SignalMessage(envelope.content.toByteArray())); + metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, envelope.serverGuid, Optional.empty(), envelope.destinationServiceId); + } else if (envelope.type == Envelope.Type.PLAINTEXT_CONTENT) { + paddedMessage = new PlaintextContent(envelope.content.toByteArray()).getBody(); + metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, envelope.serverGuid, Optional.empty(), envelope.destinationServiceId); + } else if (envelope.type == Envelope.Type.UNIDENTIFIED_SENDER) { SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber().orElse(null), localDeviceId)); - DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, envelope.getContent().toByteArray(), envelope.getServerTimestamp()); + DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, envelope.content.toByteArray(), envelope.serverTimestamp); SignalServiceAddress resultAddress = new SignalServiceAddress(ACI.parseOrThrow(result.getSenderUuid()), result.getSenderE164()); Optional groupId = result.getGroupId(); boolean needsReceipt = true; - if (envelope.hasSourceServiceId()) { - Log.w(TAG, "[" + envelope.getTimestamp() + "] Received a UD-encrypted message sent over an identified channel. Marking as needsReceipt=false"); + if (envelope.sourceServiceId != null) { + Log.w(TAG, "[" + envelope.timestamp + "] Received a UD-encrypted message sent over an identified channel. Marking as needsReceipt=false"); needsReceipt = false; } @@ -210,9 +209,9 @@ public class SignalServiceCipher { } paddedMessage = result.getPaddedMessage(); - metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerTimestamp(), serverDeliveredTimestamp, needsReceipt, envelope.getServerGuid(), groupId, envelope.getDestinationServiceId()); + metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, needsReceipt, envelope.serverGuid, groupId, envelope.destinationServiceId); } else { - throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType()); + throw new InvalidMetadataMessageException("Unknown type: " + envelope.type); } PushTransportDetails transportDetails = new PushTransportDetails(); @@ -220,26 +219,26 @@ public class SignalServiceCipher { return new Plaintext(metadata, data); } catch (DuplicateMessageException e) { - throw new ProtocolDuplicateMessageException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolDuplicateMessageException(e, envelope.sourceServiceId, envelope.sourceDevice); } catch (LegacyMessageException e) { - throw new ProtocolLegacyMessageException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolLegacyMessageException(e, envelope.sourceServiceId, envelope.sourceDevice); } catch (InvalidMessageException e) { - throw new ProtocolInvalidMessageException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolInvalidMessageException(e, envelope.sourceServiceId, envelope.sourceDevice); } catch (InvalidKeyIdException e) { - throw new ProtocolInvalidKeyIdException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolInvalidKeyIdException(e, envelope.sourceServiceId, envelope.sourceDevice); } catch (InvalidKeyException e) { - throw new ProtocolInvalidKeyException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolInvalidKeyException(e, envelope.sourceServiceId, envelope.sourceDevice); } catch (UntrustedIdentityException e) { - throw new ProtocolUntrustedIdentityException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolUntrustedIdentityException(e, envelope.sourceServiceId, envelope.sourceDevice); } catch (InvalidVersionException e) { - throw new ProtocolInvalidVersionException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolInvalidVersionException(e, envelope.sourceServiceId, envelope.sourceDevice); } catch (NoSessionException e) { - throw new ProtocolNoSessionException(e, envelope.getSourceServiceId(), envelope.getSourceDevice()); + throw new ProtocolNoSessionException(e, envelope.sourceServiceId, envelope.sourceDevice); } } private static SignalServiceAddress getSourceAddress(Envelope envelope) { - return new SignalServiceAddress(ServiceId.parseOrNull(envelope.getSourceServiceId())); + return new SignalServiceAddress(ServiceId.parseOrNull(envelope.sourceServiceId)); } private static class Plaintext { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipherResult.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipherResult.kt index c496f4e8c5..fe1ac0da13 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipherResult.kt +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipherResult.kt @@ -1,6 +1,6 @@ package org.whispersystems.signalservice.api.crypto -import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.internal.push.Content /** * Represents the output of decrypting a [SignalServiceProtos.Envelope] via [SignalServiceCipher.decrypt] @@ -10,6 +10,6 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos * been encrypted with sealed sender. */ data class SignalServiceCipherResult( - val content: SignalServiceProtos.Content, + val content: Content, val metadata: EnvelopeMetadata ) diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.java deleted file mode 100644 index 44f1c2cc98..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.java +++ /dev/null @@ -1,158 +0,0 @@ -package org.whispersystems.signalservice.api.groupsv2; - -import com.google.protobuf.ByteString; - -import org.signal.storageservice.protos.groups.Member; -import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; -import org.signal.storageservice.protos.groups.local.DecryptedMember; -import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; - -import java.util.ArrayList; -import java.util.List; - -final class DecryptedGroupChangeActionsBuilderChangeSetModifier implements ChangeSetModifier { - private final DecryptedGroupChange.Builder result; - - public DecryptedGroupChangeActionsBuilderChangeSetModifier(DecryptedGroupChange.Builder result) { - this.result = result; - } - - @Override - public void removeAddMembers(int i) { - result.removeNewMembers(i); - } - - @Override - public void moveAddToPromote(int i) { - DecryptedMember addMemberAction = result.getNewMembersList().get(i); - result.removeNewMembers(i); - result.addPromotePendingMembers(addMemberAction); - } - - @Override - public void removeDeleteMembers(int i) { - List newList = removeIndexFromByteStringList(result.getDeleteMembersList(), i); - - result.clearDeleteMembers() - .addAllDeleteMembers(newList); - } - - @Override - public void removeModifyMemberRoles(int i) { - result.removeModifyMemberRoles(i); - } - - @Override - public void removeModifyMemberProfileKeys(int i) { - result.removeModifiedProfileKeys(i); - } - - @Override - public void removeAddPendingMembers(int i) { - result.removeNewPendingMembers(i); - } - - @Override - public void removeDeletePendingMembers(int i) { - result.removeDeletePendingMembers(i); - } - - @Override - public void removePromotePendingMembers(int i) { - result.removePromotePendingMembers(i); - } - - @Override - public void clearModifyTitle() { - result.clearNewTitle(); - } - - @Override - public void clearModifyAvatar() { - result.clearNewAvatar(); - } - - @Override - public void clearModifyDisappearingMessagesTimer() { - result.clearNewTimer(); - } - - @Override - public void clearModifyAttributesAccess() { - result.clearNewAttributeAccess(); - } - - @Override - public void clearModifyMemberAccess() { - result.clearNewMemberAccess(); - } - - @Override - public void clearModifyAddFromInviteLinkAccess() { - result.clearNewInviteLinkAccess(); - } - - @Override - public void removeAddRequestingMembers(int i) { - result.removeNewRequestingMembers(i); - } - - @Override - public void moveAddRequestingMembersToPromote(int i) { - DecryptedRequestingMember addMemberAction = result.getNewRequestingMembersList().get(i); - result.removeNewRequestingMembers(i); - - DecryptedMember build = DecryptedMember.newBuilder() - .setAciBytes(addMemberAction.getAciBytes()) - .setProfileKey(addMemberAction.getProfileKey()) - .setRole(Member.Role.DEFAULT).build(); - - result.addPromotePendingMembers(0, build); - } - - @Override - public void removeDeleteRequestingMembers(int i) { - List newList = removeIndexFromByteStringList(result.getDeleteRequestingMembersList(), i); - - result.clearDeleteRequestingMembers() - .addAllDeleteRequestingMembers(newList); - } - - @Override - public void removePromoteRequestingMembers(int i) { - result.removePromoteRequestingMembers(i); - } - - @Override - public void clearModifyDescription() { - result.clearNewDescription(); - } - - @Override - public void clearModifyAnnouncementsOnly() { - result.clearNewIsAnnouncementGroup(); - } - - @Override - public void removeAddBannedMembers(int i) { - result.removeNewBannedMembers(i); - } - - @Override - public void removeDeleteBannedMembers(int i) { - result.removeDeleteBannedMembers(i); - } - - @Override - public void removePromotePendingPniAciMembers(int i) { - result.removePromotePendingPniAciMembers(i); - } - - private static List removeIndexFromByteStringList(List byteStrings, int i) { - List modifiedList = new ArrayList<>(byteStrings); - - modifiedList.remove(i); - - return modifiedList; - } -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.kt new file mode 100644 index 0000000000..c69e441579 --- /dev/null +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupChangeActionsBuilderChangeSetModifier.kt @@ -0,0 +1,118 @@ +package org.whispersystems.signalservice.api.groupsv2 + +import org.signal.storageservice.protos.groups.AccessControl +import org.signal.storageservice.protos.groups.Member +import org.signal.storageservice.protos.groups.local.DecryptedGroupChange +import org.signal.storageservice.protos.groups.local.DecryptedMember +import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember +import org.signal.storageservice.protos.groups.local.EnabledState + +internal class DecryptedGroupChangeActionsBuilderChangeSetModifier(private val result: DecryptedGroupChange.Builder) : ChangeSetModifier { + override fun removeAddMembers(i: Int) { + result.newMembers = result.newMembers.removeIndex(i) + } + + override fun moveAddToPromote(i: Int) { + val addMemberAction: DecryptedMember = result.newMembers[i] + result.newMembers = result.newMembers.removeIndex(i) + result.promotePendingMembers += addMemberAction + } + + override fun removeDeleteMembers(i: Int) { + result.deleteMembers = result.deleteMembers.removeIndex(i) + } + + override fun removeModifyMemberRoles(i: Int) { + result.modifyMemberRoles = result.modifyMemberRoles.removeIndex(i) + } + + override fun removeModifyMemberProfileKeys(i: Int) { + result.modifiedProfileKeys = result.modifiedProfileKeys.removeIndex(i) + } + + override fun removeAddPendingMembers(i: Int) { + result.newPendingMembers = result.newPendingMembers.removeIndex(i) + } + + override fun removeDeletePendingMembers(i: Int) { + result.deletePendingMembers = result.deletePendingMembers.removeIndex(i) + } + + override fun removePromotePendingMembers(i: Int) { + result.promotePendingMembers = result.promotePendingMembers.removeIndex(i) + } + + override fun clearModifyTitle() { + result.newTitle = null + } + + override fun clearModifyAvatar() { + result.newAvatar = null + } + + override fun clearModifyDisappearingMessagesTimer() { + result.newTimer = null + } + + override fun clearModifyAttributesAccess() { + result.newAttributeAccess = AccessControl.AccessRequired.UNKNOWN + } + + override fun clearModifyMemberAccess() { + result.newMemberAccess = AccessControl.AccessRequired.UNKNOWN + } + + override fun clearModifyAddFromInviteLinkAccess() { + result.newInviteLinkAccess = AccessControl.AccessRequired.UNKNOWN + } + + override fun removeAddRequestingMembers(i: Int) { + result.newRequestingMembers = result.newRequestingMembers.removeIndex(i) + } + + override fun moveAddRequestingMembersToPromote(i: Int) { + val addMemberAction: DecryptedRequestingMember = result.newRequestingMembers[i] + result.newRequestingMembers = result.newRequestingMembers.removeIndex(i) + + val promote = DecryptedMember( + aciBytes = addMemberAction.aciBytes, + profileKey = addMemberAction.profileKey, + role = Member.Role.DEFAULT + ) + result.promotePendingMembers += promote + } + + override fun removeDeleteRequestingMembers(i: Int) { + result.deleteRequestingMembers = result.deleteRequestingMembers.removeIndex(i) + } + + override fun removePromoteRequestingMembers(i: Int) { + result.promoteRequestingMembers = result.promoteRequestingMembers.removeIndex(i) + } + + override fun clearModifyDescription() { + result.newDescription = null + } + + override fun clearModifyAnnouncementsOnly() { + result.newIsAnnouncementGroup = EnabledState.UNKNOWN + } + + override fun removeAddBannedMembers(i: Int) { + result.newBannedMembers = result.newBannedMembers.removeIndex(i) + } + + override fun removeDeleteBannedMembers(i: Int) { + result.deleteBannedMembers = result.deleteBannedMembers.removeIndex(i) + } + + override fun removePromotePendingPniAciMembers(i: Int) { + result.promotePendingPniAciMembers = result.promotePendingPniAciMembers.removeIndex(i) + } + + private fun List.removeIndex(i: Int): List { + val modifiedList = this.toMutableList() + modifiedList.removeAt(i) + return modifiedList + } +} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupHistoryEntry.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupHistoryEntry.java index dfcfc0ba76..4ca34c221e 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupHistoryEntry.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupHistoryEntry.java @@ -17,7 +17,7 @@ public final class DecryptedGroupHistoryEntry { public DecryptedGroupHistoryEntry(Optional group, Optional change) throws InvalidGroupStateException { - if (group.isPresent() && change.isPresent() && group.get().getRevision() != change.get().getRevision()) { + if (group.isPresent() && change.isPresent() && group.get().revision != change.get().revision) { throw new InvalidGroupStateException(); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java index 80435bf245..d1552510e5 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.signal.libsignal.protocol.logging.Log; import org.signal.storageservice.protos.groups.AccessControl; import org.signal.storageservice.protos.groups.Member; @@ -28,6 +26,8 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import okio.ByteString; + public final class DecryptedGroupUtil { private static final String TAG = DecryptedGroupUtil.class.getSimpleName(); @@ -36,7 +36,7 @@ public final class DecryptedGroupUtil { ArrayList serviceIdList = new ArrayList<>(membersList.size()); for (DecryptedMember member : membersList) { - serviceIdList.add(ACI.parseOrUnknown(member.getAciBytes())); + serviceIdList.add(ACI.parseOrUnknown(member.aciBytes)); } return serviceIdList; @@ -47,7 +47,7 @@ public final class DecryptedGroupUtil { ArrayList serviceIdList = new ArrayList<>(membersList.size()); for (DecryptedMember member : membersList) { - ACI aci = ACI.parseOrNull(member.getAciBytes()); + ACI aci = ACI.parseOrNull(member.aciBytes); if (aci != null) { serviceIdList.add(aci); @@ -61,7 +61,7 @@ public final class DecryptedGroupUtil { Set aciList = new HashSet<>(membersList.size()); for (DecryptedMember member : membersList) { - aciList.add(member.getAciBytes()); + aciList.add(member.aciBytes); } return aciList; @@ -74,7 +74,7 @@ public final class DecryptedGroupUtil { ArrayList serviceIdList = new ArrayList<>(membersList.size()); for (DecryptedPendingMember member : membersList) { - ServiceId serviceId = ServiceId.parseOrNull(member.getServiceIdBytes()); + ServiceId serviceId = ServiceId.parseOrNull(member.serviceIdBytes); if (serviceId != null) { serviceIdList.add(serviceId); } else { @@ -89,7 +89,7 @@ public final class DecryptedGroupUtil { * Will not return any non-decryptable member ACIs. */ public static ArrayList removedMembersServiceIdList(DecryptedGroupChange groupChange) { - List deletedMembers = groupChange.getDeleteMembersList(); + List deletedMembers = groupChange.deleteMembers; ArrayList serviceIdList = new ArrayList<>(deletedMembers.size()); for (ByteString member : deletedMembers) { @@ -107,11 +107,11 @@ public final class DecryptedGroupUtil { * Will not return any non-decryptable member ACIs. */ public static ArrayList removedPendingMembersServiceIdList(DecryptedGroupChange groupChange) { - List deletedPendingMembers = groupChange.getDeletePendingMembersList(); + List deletedPendingMembers = groupChange.deletePendingMembers; ArrayList serviceIdList = new ArrayList<>(deletedPendingMembers.size()); for (DecryptedPendingMemberRemoval member : deletedPendingMembers) { - ServiceId serviceId = ServiceId.parseOrNull(member.getServiceIdBytes()); + ServiceId serviceId = ServiceId.parseOrNull(member.serviceIdBytes); if(serviceId != null) { serviceIdList.add(serviceId); @@ -125,7 +125,7 @@ public final class DecryptedGroupUtil { * Will not return any non-decryptable member ACIs. */ public static ArrayList removedRequestingMembersServiceIdList(DecryptedGroupChange groupChange) { - List deleteRequestingMembers = groupChange.getDeleteRequestingMembersList(); + List deleteRequestingMembers = groupChange.deleteRequestingMembers; ArrayList serviceIdList = new ArrayList<>(deleteRequestingMembers.size()); for (ByteString member : deleteRequestingMembers) { @@ -143,7 +143,7 @@ public final class DecryptedGroupUtil { Set serviceIdSet = new HashSet<>(membersList.size()); for (DecryptedBannedMember member : membersList) { - ServiceId serviceId = ServiceId.parseOrNull(member.getServiceIdBytes()); + ServiceId serviceId = ServiceId.parseOrNull(member.serviceIdBytes); if (serviceId != null) { serviceIdSet.add(serviceId); } @@ -156,14 +156,14 @@ public final class DecryptedGroupUtil { * The ACI of the member that made the change. */ public static Optional editorServiceId(DecryptedGroupChange change) { - return Optional.ofNullable(change != null ? ServiceId.parseOrNull(change.getEditorServiceIdBytes()) : null); + return Optional.ofNullable(change != null ? ServiceId.parseOrNull(change.editorServiceIdBytes) : null); } public static Optional findMemberByAci(Collection members, ACI aci) { ByteString aciBytes = aci.toByteString(); for (DecryptedMember member : members) { - if (aciBytes.equals(member.getAciBytes())) { + if (aciBytes.equals(member.aciBytes)) { return Optional.of(member); } } @@ -175,7 +175,7 @@ public final class DecryptedGroupUtil { ByteString serviceIdBinary = serviceId.toByteString(); for (DecryptedPendingMember member : members) { - if (serviceIdBinary.equals(member.getServiceIdBytes())) { + if (serviceIdBinary.equals(member.serviceIdBytes)) { return Optional.of(member); } } @@ -185,7 +185,7 @@ public final class DecryptedGroupUtil { public static Optional findPendingByServiceIds(Collection members, ServiceIds serviceIds) { for (DecryptedPendingMember member : members) { - if (serviceIds.matches(member.getServiceIdBytes())) { + if (serviceIds.matches(member.serviceIdBytes)) { return Optional.of(member); } } @@ -196,7 +196,7 @@ public final class DecryptedGroupUtil { private static int findPendingIndexByServiceIdCipherText(List members, ByteString cipherText) { for (int i = 0; i < members.size(); i++) { DecryptedPendingMember member = members.get(i); - if (cipherText.equals(member.getServiceIdCipherText())) { + if (cipherText.equals(member.serviceIdCipherText)) { return i; } } @@ -207,7 +207,7 @@ public final class DecryptedGroupUtil { private static int findPendingIndexByServiceId(List members, ByteString serviceIdBinary) { for (int i = 0; i < members.size(); i++) { DecryptedPendingMember member = members.get(i); - if (serviceIdBinary.equals(member.getServiceIdBytes())) { + if (serviceIdBinary.equals(member.serviceIdBytes)) { return i; } } @@ -219,7 +219,7 @@ public final class DecryptedGroupUtil { ByteString aciBytes = aci.toByteString(); for (DecryptedRequestingMember member : members) { - if (aciBytes.equals(member.getAciBytes())) { + if (aciBytes.equals(member.aciBytes)) { return Optional.of(member); } } @@ -229,7 +229,7 @@ public final class DecryptedGroupUtil { public static Optional findRequestingByServiceIds(Collection members, ServiceIds serviceIds) { for (DecryptedRequestingMember member : members) { - if (serviceIds.matches(member.getAciBytes())) { + if (serviceIds.matches(member.aciBytes)) { return Optional.of(member); } } @@ -238,12 +238,12 @@ public final class DecryptedGroupUtil { } public static boolean isPendingOrRequesting(DecryptedGroup group, ServiceIds serviceIds) { - return findPendingByServiceIds(group.getPendingMembersList(), serviceIds).isPresent() || - findRequestingByServiceIds(group.getRequestingMembersList(), serviceIds).isPresent(); + return findPendingByServiceIds(group.pendingMembers, serviceIds).isPresent() || + findRequestingByServiceIds(group.requestingMembers, serviceIds).isPresent(); } public static boolean isRequesting(DecryptedGroup group, ACI aci) { - return findRequestingByAci(group.getRequestingMembersList(), aci).isPresent(); + return findRequestingByAci(group.requestingMembers, aci).isPresent(); } /** @@ -253,23 +253,22 @@ public final class DecryptedGroupUtil { * get the new group state as you are not in the group any longer. */ public static DecryptedGroup removeMember(DecryptedGroup group, ACI aci, int revision) { - DecryptedGroup.Builder builder = DecryptedGroup.newBuilder(group); + DecryptedGroup.Builder builder = group.newBuilder(); ByteString aciByteString = aci.toByteString(); boolean removed = false; - ArrayList decryptedMembers = new ArrayList<>(builder.getMembersList()); + ArrayList decryptedMembers = new ArrayList<>(builder.members); Iterator membersList = decryptedMembers.iterator(); while (membersList.hasNext()) { - if (aciByteString.equals(membersList.next().getAciBytes())) { + if (aciByteString.equals(membersList.next().aciBytes)) { membersList.remove(); removed = true; } } if (removed) { - return builder.clearMembers() - .addAllMembers(decryptedMembers) - .setRevision(revision) + return builder.members(decryptedMembers) + .revision(revision) .build(); } else { return group; @@ -279,7 +278,7 @@ public final class DecryptedGroupUtil { public static DecryptedGroup apply(DecryptedGroup group, DecryptedGroupChange change) throws NotAbleToApplyGroupV2ChangeException { - if (change.getRevision() != group.getRevision() + 1) { + if (change.revision != group.revision + 1) { throw new NotAbleToApplyGroupV2ChangeException(); } @@ -289,22 +288,22 @@ public final class DecryptedGroupUtil { public static DecryptedGroup applyWithoutRevisionCheck(DecryptedGroup group, DecryptedGroupChange change) throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup.Builder builder = DecryptedGroup.newBuilder(group) - .setRevision(change.getRevision()); + DecryptedGroup.Builder builder = group.newBuilder() + .revision(change.revision); - applyAddMemberAction(builder, change.getNewMembersList()); + applyAddMemberAction(builder, change.newMembers); - applyDeleteMemberActions(builder, change.getDeleteMembersList()); + applyDeleteMemberActions(builder, change.deleteMembers); - applyModifyMemberRoleActions(builder, change.getModifyMemberRolesList()); + applyModifyMemberRoleActions(builder, change.modifyMemberRoles); - applyModifyMemberProfileKeyActions(builder, change.getModifiedProfileKeysList()); + applyModifyMemberProfileKeyActions(builder, change.modifiedProfileKeys); - applyAddPendingMemberActions(builder, change.getNewPendingMembersList()); + applyAddPendingMemberActions(builder, change.newPendingMembers); - applyDeletePendingMemberActions(builder, change.getDeletePendingMembersList()); + applyDeletePendingMemberActions(builder, change.deletePendingMembers); - applyPromotePendingMemberActions(builder, change.getPromotePendingMembersList()); + applyPromotePendingMemberActions(builder, change.promotePendingMembers); applyModifyTitleAction(builder, change); @@ -322,19 +321,19 @@ public final class DecryptedGroupUtil { applyModifyAddFromInviteLinkAccessControlAction(builder, change); - applyAddRequestingMembers(builder, change.getNewRequestingMembersList()); + applyAddRequestingMembers(builder, change.newRequestingMembers); - applyDeleteRequestingMembers(builder, change.getDeleteRequestingMembersList()); + applyDeleteRequestingMembers(builder, change.deleteRequestingMembers); - applyPromoteRequestingMemberActions(builder, change.getPromoteRequestingMembersList()); + applyPromoteRequestingMemberActions(builder, change.promoteRequestingMembers); applyInviteLinkPassword(builder, change); - applyAddBannedMembersActions(builder, change.getNewBannedMembersList()); + applyAddBannedMembersActions(builder, change.newBannedMembers); - applyDeleteBannedMembersActions(builder, change.getDeleteBannedMembersList()); + applyDeleteBannedMembersActions(builder, change.deleteBannedMembers); - applyPromotePendingPniAciMemberActions(builder, change.getPromotePendingPniAciMembersList()); + applyPromotePendingPniAciMemberActions(builder, change.promotePendingPniAciMembers); return builder.build(); } @@ -344,255 +343,301 @@ public final class DecryptedGroupUtil { LinkedHashMap members = new LinkedHashMap<>(); - for (DecryptedMember member : builder.getMembersList()) { - members.put(member.getAciBytes(), member); + for (DecryptedMember member : builder.members) { + members.put(member.aciBytes, member); } for (DecryptedMember member : newMembersList) { - members.put(member.getAciBytes(), member); + members.put(member.aciBytes, member); } - builder.clearMembers(); - builder.addAllMembers(members.values()); + builder.members(new ArrayList<>(members.values())); removePendingAndRequestingMembersNowInGroup(builder); } - protected static void applyDeleteMemberActions(DecryptedGroup.Builder builder, List deleteMembersList) { + private static void applyDeleteMemberActions(DecryptedGroup.Builder builder, List deleteMembersList) { + List members = new ArrayList<>(builder.members); + for (ByteString removedMember : deleteMembersList) { - int index = indexOfAci(builder.getMembersList(), removedMember); + int index = indexOfAci(members, removedMember); if (index == -1) { Log.w(TAG, "Deleted member on change not found in group"); continue; } - builder.removeMembers(index); + members.remove(index); } + + builder.members(members); } private static void applyModifyMemberRoleActions(DecryptedGroup.Builder builder, List modifyMemberRolesList) throws NotAbleToApplyGroupV2ChangeException { + List members = new ArrayList<>(builder.members); + for (DecryptedModifyMemberRole modifyMemberRole : modifyMemberRolesList) { - int index = indexOfAci(builder.getMembersList(), modifyMemberRole.getAciBytes()); + int index = indexOfAci(members, modifyMemberRole.aciBytes); if (index == -1) { throw new NotAbleToApplyGroupV2ChangeException(); } - Member.Role role = modifyMemberRole.getRole(); + Member.Role role = modifyMemberRole.role; ensureKnownRole(role); - builder.setMembers(index, DecryptedMember.newBuilder(builder.getMembers(index)) - .setRole(role)); + members.set(index, members.get(index).newBuilder().role(role).build()); } + + builder.members(members); } private static void applyModifyMemberProfileKeyActions(DecryptedGroup.Builder builder, List modifiedProfileKeysList) throws NotAbleToApplyGroupV2ChangeException { + List members = new ArrayList<>(builder.members); + for (DecryptedMember modifyProfileKey : modifiedProfileKeysList) { - int index = indexOfAci(builder.getMembersList(), modifyProfileKey.getAciBytes()); + int index = indexOfAci(members, modifyProfileKey.aciBytes); if (index == -1) { throw new NotAbleToApplyGroupV2ChangeException(); } - builder.setMembers(index, withNewProfileKey(builder.getMembers(index), modifyProfileKey.getProfileKey())); + members.set(index, withNewProfileKey(members.get(index), modifyProfileKey.profileKey)); } + + builder.members(members); } private static void applyAddPendingMemberActions(DecryptedGroup.Builder builder, List newPendingMembersList) throws NotAbleToApplyGroupV2ChangeException { - Set fullMemberSet = getMemberAciSet(builder.getMembersList()); - Set pendingMemberCipherTexts = getPendingMemberCipherTextSet(builder.getPendingMembersList()); + Set fullMemberSet = getMemberAciSet(builder.members); + Set pendingMemberCipherTexts = getPendingMemberCipherTextSet(builder.pendingMembers); + List pendingMembers = new ArrayList<>(builder.pendingMembers); for (DecryptedPendingMember pendingMember : newPendingMembersList) { - if (fullMemberSet.contains(pendingMember.getServiceIdBytes())) { + if (fullMemberSet.contains(pendingMember.serviceIdBytes)) { throw new NotAbleToApplyGroupV2ChangeException(); } - if (!pendingMemberCipherTexts.contains(pendingMember.getServiceIdCipherText())) { - builder.addPendingMembers(pendingMember); + if (!pendingMemberCipherTexts.contains(pendingMember.serviceIdCipherText)) { + pendingMembers.add(pendingMember); } } + + builder.pendingMembers(pendingMembers); } - protected static void applyDeletePendingMemberActions(DecryptedGroup.Builder builder, List deletePendingMembersList) { + private static void applyDeletePendingMemberActions(DecryptedGroup.Builder builder, List deletePendingMembersList) { + List pendingMembers = new ArrayList<>(builder.pendingMembers); + for (DecryptedPendingMemberRemoval removedMember : deletePendingMembersList) { - int index = findPendingIndexByServiceIdCipherText(builder.getPendingMembersList(), removedMember.getServiceIdCipherText()); + int index = findPendingIndexByServiceIdCipherText(pendingMembers, removedMember.serviceIdCipherText); if (index == -1) { Log.w(TAG, "Deleted pending member on change not found in group"); continue; } - builder.removePendingMembers(index); + pendingMembers.remove(index); } + + builder.pendingMembers(pendingMembers); } - protected static void applyPromotePendingMemberActions(DecryptedGroup.Builder builder, List promotePendingMembersList) throws NotAbleToApplyGroupV2ChangeException { + private static void applyPromotePendingMemberActions(DecryptedGroup.Builder builder, List promotePendingMembersList) throws NotAbleToApplyGroupV2ChangeException { + List members = new ArrayList<>(builder.members); + List pendingMembers = new ArrayList<>(builder.pendingMembers); + for (DecryptedMember newMember : promotePendingMembersList) { - int index = findPendingIndexByServiceId(builder.getPendingMembersList(), newMember.getAciBytes()); + int index = findPendingIndexByServiceId(pendingMembers, newMember.aciBytes); if (index == -1) { throw new NotAbleToApplyGroupV2ChangeException(); } - builder.removePendingMembers(index); - builder.addMembers(newMember); + pendingMembers.remove(index); + members.add(newMember); + } + + builder.pendingMembers(pendingMembers); + builder.members(members); + } + + private static void applyModifyTitleAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + if (change.newTitle != null) { + builder.title(change.newTitle.value_); } } - protected static void applyModifyTitleAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - if (change.hasNewTitle()) { - builder.setTitle(change.getNewTitle().getValue()); + private static void applyModifyDescriptionAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + if (change.newDescription != null) { + builder.description(change.newDescription.value_); } } - protected static void applyModifyDescriptionAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - if (change.hasNewDescription()) { - builder.setDescription(change.getNewDescription().getValue()); + private static void applyModifyIsAnnouncementGroupAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + if (change.newIsAnnouncementGroup != EnabledState.UNKNOWN) { + builder.isAnnouncementGroup(change.newIsAnnouncementGroup); } } - protected static void applyModifyIsAnnouncementGroupAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - if (change.getNewIsAnnouncementGroup() != EnabledState.UNKNOWN) { - builder.setIsAnnouncementGroup(change.getNewIsAnnouncementGroup()); + private static void applyModifyAvatarAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + if (change.newAvatar != null) { + builder.avatar(change.newAvatar.value_); } } - - protected static void applyModifyAvatarAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - if (change.hasNewAvatar()) { - builder.setAvatar(change.getNewAvatar().getValue()); + private static void applyModifyDisappearingMessagesTimerAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + if (change.newTimer != null) { + builder.disappearingMessagesTimer(change.newTimer); } } - protected static void applyModifyDisappearingMessagesTimerAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - if (change.hasNewTimer()) { - builder.setDisappearingMessagesTimer(change.getNewTimer()); - } - } - - protected static void applyModifyAttributesAccessControlAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - AccessControl.AccessRequired newAccessLevel = change.getNewAttributeAccess(); + private static void applyModifyAttributesAccessControlAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + AccessControl.AccessRequired newAccessLevel = change.newAttributeAccess; if (newAccessLevel != AccessControl.AccessRequired.UNKNOWN) { - builder.setAccessControl(AccessControl.newBuilder(builder.getAccessControl()) - .setAttributesValue(change.getNewAttributeAccessValue())); + AccessControl.Builder accessControlBuilder = builder.accessControl != null ? builder.accessControl.newBuilder() : new AccessControl.Builder(); + builder.accessControl(accessControlBuilder.attributes(change.newAttributeAccess).build()); } } - protected static void applyModifyMembersAccessControlAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - AccessControl.AccessRequired newAccessLevel = change.getNewMemberAccess(); + private static void applyModifyMembersAccessControlAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + AccessControl.AccessRequired newAccessLevel = change.newMemberAccess; if (newAccessLevel != AccessControl.AccessRequired.UNKNOWN) { - builder.setAccessControl(AccessControl.newBuilder(builder.getAccessControl()) - .setMembersValue(change.getNewMemberAccessValue())); + AccessControl.Builder accessControlBuilder = builder.accessControl != null ? builder.accessControl.newBuilder() : new AccessControl.Builder(); + builder.accessControl(accessControlBuilder.members(change.newMemberAccess).build()); } } - protected static void applyModifyAddFromInviteLinkAccessControlAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - AccessControl.AccessRequired newAccessLevel = change.getNewInviteLinkAccess(); + private static void applyModifyAddFromInviteLinkAccessControlAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) { + AccessControl.AccessRequired newAccessLevel = change.newInviteLinkAccess; if (newAccessLevel != AccessControl.AccessRequired.UNKNOWN) { - builder.setAccessControl(AccessControl.newBuilder(builder.getAccessControl()) - .setAddFromInviteLink(newAccessLevel)); + AccessControl.Builder accessControlBuilder = builder.accessControl != null ? builder.accessControl.newBuilder() : new AccessControl.Builder(); + builder.accessControl(accessControlBuilder.addFromInviteLink(newAccessLevel).build()); } } private static void applyAddRequestingMembers(DecryptedGroup.Builder builder, List newRequestingMembers) { - builder.addAllRequestingMembers(newRequestingMembers); + List requestingMembers = new ArrayList<>(builder.requestingMembers); + requestingMembers.addAll(newRequestingMembers); + builder.requestingMembers(requestingMembers); } private static void applyDeleteRequestingMembers(DecryptedGroup.Builder builder, List deleteRequestingMembersList) { + List requestingMembers = new ArrayList<>(builder.requestingMembers); for (ByteString removedMember : deleteRequestingMembersList) { - int index = indexOfAciInRequestingList(builder.getRequestingMembersList(), removedMember); + int index = indexOfAciInRequestingList(requestingMembers, removedMember); if (index == -1) { Log.w(TAG, "Deleted member on change not found in group"); continue; } - builder.removeRequestingMembers(index); + requestingMembers.remove(index); } + builder.requestingMembers(requestingMembers); } private static void applyPromoteRequestingMemberActions(DecryptedGroup.Builder builder, List promoteRequestingMembers) throws NotAbleToApplyGroupV2ChangeException { + List members = new ArrayList<>(builder.members); + List requestingMembers = new ArrayList<>(builder.requestingMembers); + for (DecryptedApproveMember approvedMember : promoteRequestingMembers) { - int index = indexOfAciInRequestingList(builder.getRequestingMembersList(), approvedMember.getAciBytes()); + int index = indexOfAciInRequestingList(requestingMembers, approvedMember.aciBytes); if (index == -1) { Log.w(TAG, "Deleted member on change not found in group"); continue; } - DecryptedRequestingMember requestingMember = builder.getRequestingMembers(index); - Member.Role role = approvedMember.getRole(); + DecryptedRequestingMember requestingMember = requestingMembers.get(index); + Member.Role role = approvedMember.role; ensureKnownRole(role); - builder.removeRequestingMembers(index) - .addMembers(DecryptedMember.newBuilder() - .setAciBytes(approvedMember.getAciBytes()) - .setProfileKey(requestingMember.getProfileKey()) - .setRole(role)); + requestingMembers.remove(index); + members.add(new DecryptedMember.Builder() + .aciBytes(approvedMember.aciBytes) + .profileKey(requestingMember.profileKey) + .role(role) + .build()); } + + builder.members(members); + builder.requestingMembers(requestingMembers); } private static void applyInviteLinkPassword(DecryptedGroup.Builder builder, DecryptedGroupChange change) { - if (!change.getNewInviteLinkPassword().isEmpty()) { - builder.setInviteLinkPassword(change.getNewInviteLinkPassword()); + if (change.newInviteLinkPassword.size() > 0) { + builder.inviteLinkPassword(change.newInviteLinkPassword); } } private static void applyAddBannedMembersActions(DecryptedGroup.Builder builder, List newBannedMembersList) { - Set bannedMemberServiceIdSet = getBannedMemberServiceIdSet(builder.getBannedMembersList()); + Set bannedMemberServiceIdSet = getBannedMemberServiceIdSet(builder.bannedMembers); + List bannedMembers = new ArrayList<>(builder.bannedMembers); for (DecryptedBannedMember member : newBannedMembersList) { - if (bannedMemberServiceIdSet.contains(member.getServiceIdBytes())) { + if (bannedMemberServiceIdSet.contains(member.serviceIdBytes)) { Log.w(TAG, "Banned member already in banned list"); } else { - builder.addBannedMembers(member); + bannedMembers.add(member); } } + + builder.bannedMembers(bannedMembers); } private static void applyDeleteBannedMembersActions(DecryptedGroup.Builder builder, List deleteMembersList) { + List bannedMembers = new ArrayList<>(builder.bannedMembers); + for (DecryptedBannedMember removedMember : deleteMembersList) { - int index = indexOfServiceIdInBannedMemberList(builder.getBannedMembersList(), removedMember.getServiceIdBytes()); + int index = indexOfServiceIdInBannedMemberList(bannedMembers, removedMember.serviceIdBytes); if (index == -1) { Log.w(TAG, "Deleted banned member on change not found in banned list"); continue; } - builder.removeBannedMembers(index); + bannedMembers.remove(index); } + + builder.bannedMembers(bannedMembers); } - protected static void applyPromotePendingPniAciMemberActions(DecryptedGroup.Builder builder, List promotePendingPniAciMembersList) throws NotAbleToApplyGroupV2ChangeException { + private static void applyPromotePendingPniAciMemberActions(DecryptedGroup.Builder builder, List promotePendingPniAciMembersList) throws NotAbleToApplyGroupV2ChangeException { + List members = new ArrayList<>(builder.members); + List pendingMembers = new ArrayList<>(builder.pendingMembers); + for (DecryptedMember newMember : promotePendingPniAciMembersList) { - int index = findPendingIndexByServiceId(builder.getPendingMembersList(), newMember.getPniBytes()); + int index = findPendingIndexByServiceId(pendingMembers, newMember.pniBytes); if (index == -1) { throw new NotAbleToApplyGroupV2ChangeException(); } - builder.removePendingMembers(index); - builder.addMembers(newMember); + pendingMembers.remove(index); + members.add(newMember); } + + builder.members(members); + builder.pendingMembers(pendingMembers); } private static DecryptedMember withNewProfileKey(DecryptedMember member, ByteString profileKey) { - return DecryptedMember.newBuilder(member) - .setProfileKey(profileKey) - .build(); + return member.newBuilder() + .profileKey(profileKey) + .build(); } private static Set getMemberAciSet(List membersList) { Set memberAcis = new HashSet<>(membersList.size()); for (DecryptedMember members : membersList) { - memberAcis.add(members.getAciBytes()); + memberAcis.add(members.aciBytes); } return memberAcis; @@ -602,7 +647,7 @@ public final class DecryptedGroupUtil { Set pendingMemberCipherTexts = new HashSet<>(pendingMemberList.size()); for (DecryptedPendingMember pendingMember : pendingMemberList) { - pendingMemberCipherTexts.add(pendingMember.getServiceIdCipherText()); + pendingMemberCipherTexts.add(pendingMember.serviceIdCipherText); } return pendingMemberCipherTexts; @@ -612,28 +657,32 @@ public final class DecryptedGroupUtil { Set memberServiceIds = new HashSet<>(bannedMemberList.size()); for (DecryptedBannedMember member : bannedMemberList) { - memberServiceIds.add(member.getServiceIdBytes()); + memberServiceIds.add(member.serviceIdBytes); } return memberServiceIds; } private static void removePendingAndRequestingMembersNowInGroup(DecryptedGroup.Builder builder) { - Set allMembers = membersToAciByteStringSet(builder.getMembersList()); + Set allMembers = membersToAciByteStringSet(builder.members); - for (int i = builder.getPendingMembersCount() - 1; i >= 0; i--) { - DecryptedPendingMember pendingMember = builder.getPendingMembers(i); - if (allMembers.contains(pendingMember.getServiceIdBytes())) { - builder.removePendingMembers(i); + List pendingMembers = new ArrayList<>(builder.pendingMembers); + for (int i = pendingMembers.size() - 1; i >= 0; i--) { + DecryptedPendingMember pendingMember = pendingMembers.get(i); + if (allMembers.contains(pendingMember.serviceIdBytes)) { + pendingMembers.remove(i); } } + builder.pendingMembers(pendingMembers); - for (int i = builder.getRequestingMembersCount() - 1; i >= 0; i--) { - DecryptedRequestingMember requestingMember = builder.getRequestingMembers(i); - if (allMembers.contains(requestingMember.getAciBytes())) { - builder.removeRequestingMembers(i); + List requestingMembers = new ArrayList<>(builder.requestingMembers); + for (int i = requestingMembers.size() - 1; i >= 0; i--) { + DecryptedRequestingMember requestingMember = requestingMembers.get(i); + if (allMembers.contains(requestingMember.aciBytes)) { + requestingMembers.remove(i); } } + builder.requestingMembers(requestingMembers); } private static void ensureKnownRole(Member.Role role) throws NotAbleToApplyGroupV2ChangeException { @@ -644,7 +693,7 @@ public final class DecryptedGroupUtil { private static int indexOfAci(List memberList, ByteString aci) { for (int i = 0; i < memberList.size(); i++) { - if (aci.equals(memberList.get(i).getAciBytes())) { + if (aci.equals(memberList.get(i).aciBytes)) { return i; } } @@ -653,7 +702,7 @@ public final class DecryptedGroupUtil { private static int indexOfAciInRequestingList(List memberList, ByteString aci) { for (int i = 0; i < memberList.size(); i++) { - if (aci.equals(memberList.get(i).getAciBytes())) { + if (aci.equals(memberList.get(i).aciBytes)) { return i; } } @@ -662,7 +711,7 @@ public final class DecryptedGroupUtil { private static int indexOfServiceIdInBannedMemberList(List memberList, ByteString serviceIdBinary) { for (int i = 0; i < memberList.size(); i++) { - if (serviceIdBinary.equals(memberList.get(i).getServiceIdBytes())) { + if (serviceIdBinary.equals(memberList.get(i).serviceIdBytes)) { return i; } } @@ -670,7 +719,7 @@ public final class DecryptedGroupUtil { } public static boolean changeIsEmpty(DecryptedGroupChange change) { - return change.getModifiedProfileKeysCount() == 0 && // field 6 + return change.modifiedProfileKeys.size() == 0 && // field 6 changeIsEmptyExceptForProfileKeyChanges(change); } @@ -678,50 +727,50 @@ public final class DecryptedGroupUtil { * When updating this, update {@link #changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(DecryptedGroupChange)} */ public static boolean changeIsEmptyExceptForProfileKeyChanges(DecryptedGroupChange change) { - return change.getNewMembersCount() == 0 && // field 3 - change.getDeleteMembersCount() == 0 && // field 4 - change.getModifyMemberRolesCount() == 0 && // field 5 - change.getNewPendingMembersCount() == 0 && // field 7 - change.getDeletePendingMembersCount() == 0 && // field 8 - change.getPromotePendingMembersCount() == 0 && // field 9 - !change.hasNewTitle() && // field 10 - !change.hasNewAvatar() && // field 11 - !change.hasNewTimer() && // field 12 - isEmpty(change.getNewAttributeAccess()) && // field 13 - isEmpty(change.getNewMemberAccess()) && // field 14 - isEmpty(change.getNewInviteLinkAccess()) && // field 15 - change.getNewRequestingMembersCount() == 0 && // field 16 - change.getDeleteRequestingMembersCount() == 0 && // field 17 - change.getPromoteRequestingMembersCount() == 0 && // field 18 - change.getNewInviteLinkPassword().size() == 0 && // field 19 - !change.hasNewDescription() && // field 20 - isEmpty(change.getNewIsAnnouncementGroup()) && // field 21 - change.getNewBannedMembersCount() == 0 && // field 22 - change.getDeleteBannedMembersCount() == 0 && // field 23 - change.getPromotePendingPniAciMembersCount() == 0; // field 24 + return change.newMembers.size() == 0 && // field 3 + change.deleteMembers.size() == 0 && // field 4 + change.modifyMemberRoles.size() == 0 && // field 5 + change.newPendingMembers.size() == 0 && // field 7 + change.deletePendingMembers.size() == 0 && // field 8 + change.promotePendingMembers.size() == 0 && // field 9 + change.newTitle == null && // field 10 + change.newAvatar == null && // field 11 + change.newTimer == null && // field 12 + isEmpty(change.newAttributeAccess) && // field 13 + isEmpty(change.newMemberAccess) && // field 14 + isEmpty(change.newInviteLinkAccess) && // field 15 + change.newRequestingMembers.size() == 0 && // field 16 + change.deleteRequestingMembers.size() == 0 && // field 17 + change.promoteRequestingMembers.size() == 0 && // field 18 + change.newInviteLinkPassword.size() == 0 && // field 19 + change.newDescription == null && // field 20 + isEmpty(change.newIsAnnouncementGroup) && // field 21 + change.newBannedMembers.size() == 0 && // field 22 + change.deleteBannedMembers.size() == 0 && // field 23 + change.promotePendingPniAciMembers.size() == 0; // field 24 } public static boolean changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(DecryptedGroupChange change) { - return (change.getNewBannedMembersCount() != 0 || change.getDeleteBannedMembersCount() != 0) && - change.getNewMembersCount() == 0 && // field 3 - change.getDeleteMembersCount() == 0 && // field 4 - change.getModifyMemberRolesCount() == 0 && // field 5 - change.getNewPendingMembersCount() == 0 && // field 7 - change.getDeletePendingMembersCount() == 0 && // field 8 - change.getPromotePendingMembersCount() == 0 && // field 9 - !change.hasNewTitle() && // field 10 - !change.hasNewAvatar() && // field 11 - !change.hasNewTimer() && // field 12 - isEmpty(change.getNewAttributeAccess()) && // field 13 - isEmpty(change.getNewMemberAccess()) && // field 14 - isEmpty(change.getNewInviteLinkAccess()) && // field 15 - change.getNewRequestingMembersCount() == 0 && // field 16 - change.getDeleteRequestingMembersCount() == 0 && // field 17 - change.getPromoteRequestingMembersCount() == 0 && // field 18 - change.getNewInviteLinkPassword().size() == 0 && // field 19 - !change.hasNewDescription() && // field 20 - isEmpty(change.getNewIsAnnouncementGroup()) && // field 21 - change.getPromotePendingPniAciMembersCount() == 0; // field 24 + return (change.newBannedMembers.size() != 0 || change.deleteBannedMembers.size() != 0) && + change.newMembers.size() == 0 && // field 3 + change.deleteMembers.size() == 0 && // field 4 + change.modifyMemberRoles.size() == 0 && // field 5 + change.newPendingMembers.size() == 0 && // field 7 + change.deletePendingMembers.size() == 0 && // field 8 + change.promotePendingMembers.size() == 0 && // field 9 + change.newTitle == null && // field 10 + change.newAvatar == null && // field 11 + change.newTimer == null && // field 12 + isEmpty(change.newAttributeAccess) && // field 13 + isEmpty(change.newMemberAccess) && // field 14 + isEmpty(change.newInviteLinkAccess) && // field 15 + change.newRequestingMembers.size() == 0 && // field 16 + change.deleteRequestingMembers.size() == 0 && // field 17 + change.promoteRequestingMembers.size() == 0 && // field 18 + change.newInviteLinkPassword.size() == 0 && // field 19 + change.newDescription == null && // field 20 + isEmpty(change.newIsAnnouncementGroup) && // field 21 + change.promotePendingPniAciMembers.size() == 0; // field 24 } static boolean isEmpty(AccessControl.AccessRequired newAttributeAccess) { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.java deleted file mode 100644 index 17bb669a76..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.whispersystems.signalservice.api.groupsv2; - -import org.signal.storageservice.protos.groups.GroupChange; - -final class GroupChangeActionsBuilderChangeSetModifier implements ChangeSetModifier { - private final GroupChange.Actions.Builder result; - - public GroupChangeActionsBuilderChangeSetModifier(GroupChange.Actions.Builder result) { - this.result = result; - } - - @Override - public void removeAddMembers(int i) { - result.removeAddMembers(i); - } - - @Override - public void moveAddToPromote(int i) { - GroupChange.Actions.AddMemberAction addMemberAction = result.getAddMembersList().get(i); - result.removeAddMembers(i); - result.addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(addMemberAction.getAdded().getPresentation())); - } - - @Override - public void removeDeleteMembers(int i) { - result.removeDeleteMembers(i); - } - - @Override - public void removeModifyMemberRoles(int i) { - result.removeModifyMemberRoles(i); - } - - @Override - public void removeModifyMemberProfileKeys(int i) { - result.removeModifyMemberProfileKeys(i); - } - - @Override - public void removeAddPendingMembers(int i) { - result.removeAddPendingMembers(i); - } - - @Override - public void removeDeletePendingMembers(int i) { - result.removeDeletePendingMembers(i); - } - - @Override - public void removePromotePendingMembers(int i) { - result.removePromotePendingMembers(i); - } - - @Override - public void clearModifyTitle() { - result.clearModifyTitle(); - } - - @Override - public void clearModifyAvatar() { - result.clearModifyAvatar(); - } - - @Override - public void clearModifyDisappearingMessagesTimer() { - result.clearModifyDisappearingMessagesTimer(); - } - - @Override - public void clearModifyAttributesAccess() { - result.clearModifyAttributesAccess(); - } - - @Override - public void clearModifyMemberAccess() { - result.clearModifyMemberAccess(); - } - - @Override - public void clearModifyAddFromInviteLinkAccess() { - result.clearModifyAddFromInviteLinkAccess(); - } - - @Override - public void removeAddRequestingMembers(int i) { - result.removeAddRequestingMembers(i); - } - - @Override - public void moveAddRequestingMembersToPromote(int i) { - GroupChange.Actions.AddRequestingMemberAction addMemberAction = result.getAddRequestingMembersList().get(i); - result.removeAddRequestingMembers(i); - result.addPromotePendingMembers(0, GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(addMemberAction.getAdded().getPresentation())); - } - - @Override - public void removeDeleteRequestingMembers(int i) { - result.removeDeleteRequestingMembers(i); - } - - @Override - public void removePromoteRequestingMembers(int i) { - result.removePromoteRequestingMembers(i); - } - - @Override - public void clearModifyDescription() { - result.clearModifyDescription(); - } - - @Override - public void clearModifyAnnouncementsOnly() { - result.clearModifyAnnouncementsOnly(); - } - - @Override - public void removeAddBannedMembers(int i) { - result.removeAddBannedMembers(i); - } - - @Override - public void removeDeleteBannedMembers(int i) { - result.removeDeleteBannedMembers(i); - } - - @Override - public void removePromotePendingPniAciMembers(int i) { - result.removePromotePendingPniAciMembers(i); - } -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.kt new file mode 100644 index 0000000000..9e5ce044b6 --- /dev/null +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeActionsBuilderChangeSetModifier.kt @@ -0,0 +1,109 @@ +package org.whispersystems.signalservice.api.groupsv2 + +import org.signal.storageservice.protos.groups.GroupChange +import org.signal.storageservice.protos.groups.GroupChange.Actions.AddMemberAction +import org.signal.storageservice.protos.groups.GroupChange.Actions.AddRequestingMemberAction + +internal class GroupChangeActionsBuilderChangeSetModifier(private val result: GroupChange.Actions.Builder) : ChangeSetModifier { + override fun removeAddMembers(i: Int) { + result.addMembers = result.addMembers.removeIndex(i) + } + + override fun moveAddToPromote(i: Int) { + val addMemberAction: AddMemberAction = result.addMembers[i] + result.addMembers = result.addMembers.removeIndex(i) + result.promotePendingMembers += GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(addMemberAction.added!!.presentation).build() + } + + override fun removeDeleteMembers(i: Int) { + result.deleteMembers = result.deleteMembers.removeIndex(i) + } + + override fun removeModifyMemberRoles(i: Int) { + result.modifyMemberRoles = result.modifyMemberRoles.removeIndex(i) + } + + override fun removeModifyMemberProfileKeys(i: Int) { + result.modifyMemberProfileKeys = result.modifyMemberProfileKeys.removeIndex(i) + } + + override fun removeAddPendingMembers(i: Int) { + result.addPendingMembers = result.addPendingMembers.removeIndex(i) + } + + override fun removeDeletePendingMembers(i: Int) { + result.deletePendingMembers = result.deletePendingMembers.removeIndex(i) + } + + override fun removePromotePendingMembers(i: Int) { + result.promotePendingMembers = result.promotePendingMembers.removeIndex(i) + } + + override fun clearModifyTitle() { + result.modifyTitle = null + } + + override fun clearModifyAvatar() { + result.modifyAvatar = null + } + + override fun clearModifyDisappearingMessagesTimer() { + result.modifyDisappearingMessagesTimer = null + } + + override fun clearModifyAttributesAccess() { + result.modifyAttributesAccess = null + } + + override fun clearModifyMemberAccess() { + result.modifyMemberAccess = null + } + + override fun clearModifyAddFromInviteLinkAccess() { + result.modifyAddFromInviteLinkAccess = null + } + + override fun removeAddRequestingMembers(i: Int) { + result.addRequestingMembers = result.addRequestingMembers.removeIndex(i) + } + + override fun moveAddRequestingMembersToPromote(i: Int) { + val addMemberAction: AddRequestingMemberAction = result.addRequestingMembers[i] + result.addRequestingMembers = result.addRequestingMembers.removeIndex(i) + result.promotePendingMembers += GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(addMemberAction.added!!.presentation).build() + } + + override fun removeDeleteRequestingMembers(i: Int) { + result.deleteRequestingMembers = result.deleteRequestingMembers.removeIndex(i) + } + + override fun removePromoteRequestingMembers(i: Int) { + result.promoteRequestingMembers = result.promoteRequestingMembers.removeIndex(i) + } + + override fun clearModifyDescription() { + result.modifyDescription = null + } + + override fun clearModifyAnnouncementsOnly() { + result.modifyAnnouncementsOnly = null + } + + override fun removeAddBannedMembers(i: Int) { + result.addBannedMembers = result.addBannedMembers.removeIndex(i) + } + + override fun removeDeleteBannedMembers(i: Int) { + result.deleteBannedMembers = result.deleteBannedMembers.removeIndex(i) + } + + override fun removePromotePendingPniAciMembers(i: Int) { + result.promotePendingPniAciMembers = result.promotePendingPniAciMembers.removeIndex(i) + } + + private fun List.removeIndex(i: Int): List { + val modifiedList = this.toMutableList() + modifiedList.removeAt(i) + return modifiedList + } +} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstruct.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstruct.java index 7049bff407..497f538dcd 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstruct.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstruct.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.signal.storageservice.protos.groups.local.DecryptedApproveMember; import org.signal.storageservice.protos.groups.local.DecryptedBannedMember; import org.signal.storageservice.protos.groups.local.DecryptedGroup; @@ -13,12 +11,17 @@ import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemov import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; import org.signal.storageservice.protos.groups.local.DecryptedString; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; + +import okio.ByteString; public final class GroupChangeReconstruct { @@ -26,48 +29,52 @@ public final class GroupChangeReconstruct { * Given a {@param fromState} and a {@param toState} creates a {@link DecryptedGroupChange} that would take the {@param fromState} to the {@param toState}. */ public static DecryptedGroupChange reconstructGroupChange(DecryptedGroup fromState, DecryptedGroup toState) { - DecryptedGroupChange.Builder builder = DecryptedGroupChange.newBuilder() - .setRevision(toState.getRevision()); + DecryptedGroupChange.Builder builder = new DecryptedGroupChange.Builder() + .revision(toState.revision); - if (!fromState.getTitle().equals(toState.getTitle())) { - builder.setNewTitle(DecryptedString.newBuilder().setValue(toState.getTitle())); + if (!fromState.title.equals(toState.title)) { + builder.newTitle(new DecryptedString.Builder().value_(toState.title).build()); } - if (!fromState.getDescription().equals(toState.getDescription())) { - builder.setNewDescription(DecryptedString.newBuilder().setValue(toState.getDescription())); + if (!fromState.description.equals(toState.description)) { + builder.newDescription(new DecryptedString.Builder().value_(toState.description).build()); } - if (!fromState.getIsAnnouncementGroup().equals(toState.getIsAnnouncementGroup())) { - builder.setNewIsAnnouncementGroup(toState.getIsAnnouncementGroup()); + if (!fromState.isAnnouncementGroup.equals(toState.isAnnouncementGroup)) { + builder.newIsAnnouncementGroup(toState.isAnnouncementGroup); } - if (!fromState.getAvatar().equals(toState.getAvatar())) { - builder.setNewAvatar(DecryptedString.newBuilder().setValue(toState.getAvatar())); + if (!fromState.avatar.equals(toState.avatar)) { + builder.newAvatar(new DecryptedString.Builder().value_(toState.avatar).build()); } - if (!fromState.getDisappearingMessagesTimer().equals(toState.getDisappearingMessagesTimer())) { - builder.setNewTimer(toState.getDisappearingMessagesTimer()); + if (!Objects.equals(fromState.disappearingMessagesTimer, toState.disappearingMessagesTimer)) { + builder.newTimer(toState.disappearingMessagesTimer); } - if (!fromState.getAccessControl().getAttributes().equals(toState.getAccessControl().getAttributes())) { - builder.setNewAttributeAccess(toState.getAccessControl().getAttributes()); + if (fromState.accessControl == null || (toState.accessControl != null && !fromState.accessControl.attributes.equals(toState.accessControl.attributes))) { + if (toState.accessControl != null) { + builder.newAttributeAccess(toState.accessControl.attributes); + } } - if (!fromState.getAccessControl().getMembers().equals(toState.getAccessControl().getMembers())) { - builder.setNewMemberAccess(toState.getAccessControl().getMembers()); + if (fromState.accessControl == null || (toState.accessControl != null && !fromState.accessControl.members.equals(toState.accessControl.members))) { + if (toState.accessControl != null) { + builder.newMemberAccess(toState.accessControl.members); + } } - Set fromStateMemberAcis = membersToSetOfAcis(fromState.getMembersList()); - Set toStateMemberAcis = membersToSetOfAcis(toState.getMembersList()); + Set fromStateMemberAcis = membersToSetOfAcis(fromState.members); + Set toStateMemberAcis = membersToSetOfAcis(toState.members); - Set pendingMembersListA = pendingMembersToSetOfServiceIds(fromState.getPendingMembersList()); - Set pendingMembersListB = pendingMembersToSetOfServiceIds(toState.getPendingMembersList()); - - Set requestingMembersListA = requestingMembersToSetOfAcis(fromState.getRequestingMembersList()); - Set requestingMembersListB = requestingMembersToSetOfAcis(toState.getRequestingMembersList()); + Set pendingMembersListA = pendingMembersToSetOfServiceIds(fromState.pendingMembers); + Set pendingMembersListB = pendingMembersToSetOfServiceIds(toState.pendingMembers); - Set bannedMembersListA = bannedMembersToSetOfServiceIds(fromState.getBannedMembersList()); - Set bannedMembersListB = bannedMembersToSetOfServiceIds(toState.getBannedMembersList()); + Set requestingMembersListA = requestingMembersToSetOfAcis(fromState.requestingMembers); + Set requestingMembersListB = requestingMembersToSetOfAcis(toState.requestingMembers); + + Set bannedMembersListA = bannedMembersToSetOfServiceIds(fromState.bannedMembers); + Set bannedMembersListB = bannedMembersToSetOfServiceIds(toState.bannedMembers); Set removedPendingMemberServiceIds = subtract(pendingMembersListA, pendingMembersListB); Set removedRequestingMemberAcis = subtract(requestingMembersListA, requestingMembersListB); @@ -80,87 +87,87 @@ public final class GroupChangeReconstruct { Set addedByInvitationAcis = intersect(newMemberAcis, removedPendingMemberServiceIds); Set addedByRequestApprovalAcis = intersect(newMemberAcis, removedRequestingMemberAcis); - Set addedMembersByInvitation = intersectByAci(toState.getMembersList(), addedByInvitationAcis); - Set addedMembersByRequestApproval = intersectByAci(toState.getMembersList(), addedByRequestApprovalAcis); - Set addedMembers = intersectByAci(toState.getMembersList(), subtract(newMemberAcis, addedByInvitationAcis, addedByRequestApprovalAcis)); - Set uninvitedMembers = intersectPendingByServiceId(fromState.getPendingMembersList(), subtract(removedPendingMemberServiceIds, addedByInvitationAcis)); - Set rejectedRequestMembers = intersectRequestingByAci(fromState.getRequestingMembersList(), subtract(removedRequestingMemberAcis, addedByRequestApprovalAcis)); + Set addedMembersByInvitation = intersectByAci(toState.members, addedByInvitationAcis); + Set addedMembersByRequestApproval = intersectByAci(toState.members, addedByRequestApprovalAcis); + Set addedMembers = intersectByAci(toState.members, subtract(newMemberAcis, addedByInvitationAcis, addedByRequestApprovalAcis)); + Set uninvitedMembers = intersectPendingByServiceId(fromState.pendingMembers, subtract(removedPendingMemberServiceIds, addedByInvitationAcis)); + Set rejectedRequestMembers = intersectRequestingByAci(fromState.requestingMembers, subtract(removedRequestingMemberAcis, addedByRequestApprovalAcis)); - for (DecryptedMember member : intersectByAci(fromState.getMembersList(), removedMemberAcis)) { - builder.addDeleteMembers(member.getAciBytes()); - } - for (DecryptedMember member : addedMembers) { - builder.addNewMembers(member); - } + builder.deleteMembers(intersectByAci(fromState.members, removedMemberAcis).stream() + .map(m -> m.aciBytes) + .collect(Collectors.toList())); - for (DecryptedMember member : addedMembersByInvitation) { - builder.addPromotePendingMembers(member); - } + builder.newMembers(new ArrayList<>(addedMembers)); - for (DecryptedPendingMember uninvitedMember : uninvitedMembers) { - builder.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(uninvitedMember.getServiceIdBytes()) - .setServiceIdCipherText(uninvitedMember.getServiceIdCipherText())); - } + builder.promotePendingMembers(new ArrayList<>(addedMembersByInvitation)); - for (DecryptedPendingMember invitedMember : intersectPendingByServiceId(toState.getPendingMembersList(), newPendingMemberServiceIds)) { - builder.addNewPendingMembers(invitedMember); - } + builder.deletePendingMembers(uninvitedMembers.stream() + .map(uninvitedMember -> new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(uninvitedMember.serviceIdBytes) + .serviceIdCipherText(uninvitedMember.serviceIdCipherText) + .build()) + .collect(Collectors.toList())); + + builder.newPendingMembers(new ArrayList<>(intersectPendingByServiceId(toState.pendingMembers, newPendingMemberServiceIds))); Set consistentMemberAcis = intersect(fromStateMemberAcis, toStateMemberAcis); - Set changedMembers = intersectByAci(subtract(toState.getMembersList(), fromState.getMembersList()), consistentMemberAcis); - Map membersAciMap = mapByAci(fromState.getMembersList()); - Map bannedMembersServiceIdMap = bannedServiceIdMap(toState.getBannedMembersList()); + Set changedMembers = intersectByAci(subtract(toState.members, fromState.members), consistentMemberAcis); + Map membersAciMap = mapByAci(fromState.members); + Map bannedMembersServiceIdMap = bannedServiceIdMap(toState.bannedMembers); + List modifiedMemberRoles = new ArrayList<>(changedMembers.size()); + List modifiedProfileKeys = new ArrayList<>(changedMembers.size()); for (DecryptedMember newState : changedMembers) { - DecryptedMember oldState = membersAciMap.get(newState.getAciBytes()); - if (oldState.getRole() != newState.getRole()) { - builder.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder() - .setAciBytes(newState.getAciBytes()) - .setRole(newState.getRole())); + DecryptedMember oldState = membersAciMap.get(newState.aciBytes); + if (oldState.role != newState.role) { + modifiedMemberRoles.add(new DecryptedModifyMemberRole.Builder() + .aciBytes(newState.aciBytes) + .role(newState.role) + .build()); } - if (!oldState.getProfileKey().equals(newState.getProfileKey())) { - builder.addModifiedProfileKeys(newState); + if (!oldState.profileKey.equals(newState.profileKey)) { + modifiedProfileKeys.add(newState); + } + } + builder.modifyMemberRoles(modifiedMemberRoles); + builder.modifiedProfileKeys(modifiedProfileKeys); + + if (fromState.accessControl == null || (toState.accessControl != null && !fromState.accessControl.addFromInviteLink.equals(toState.accessControl.addFromInviteLink))) { + if (toState.accessControl != null) { + builder.newInviteLinkAccess(toState.accessControl.addFromInviteLink); } } - if (!fromState.getAccessControl().getAddFromInviteLink().equals(toState.getAccessControl().getAddFromInviteLink())) { - builder.setNewInviteLinkAccess(toState.getAccessControl().getAddFromInviteLink()); + builder.newRequestingMembers(new ArrayList<>(intersectRequestingByAci(toState.requestingMembers, newRequestingMemberAcis))); + + builder.deleteRequestingMembers(rejectedRequestMembers.stream().map(requestingMember -> requestingMember.aciBytes).collect(Collectors.toList())); + + builder.promoteRequestingMembers(addedMembersByRequestApproval.stream() + .map(member -> new DecryptedApproveMember.Builder() + .aciBytes(member.aciBytes) + .role(member.role) + .build()) + .collect(Collectors.toList())); + + if (!fromState.inviteLinkPassword.equals(toState.inviteLinkPassword)) { + builder.newInviteLinkPassword(toState.inviteLinkPassword); } - for (DecryptedRequestingMember requestingMember : intersectRequestingByAci(toState.getRequestingMembersList(), newRequestingMemberAcis)) { - builder.addNewRequestingMembers(requestingMember); - } - - for (DecryptedRequestingMember requestingMember : rejectedRequestMembers) { - builder.addDeleteRequestingMembers(requestingMember.getAciBytes()); - } + builder.deleteBannedMembers(removedBannedMemberServiceIds.stream().map(serviceIdBinary -> new DecryptedBannedMember.Builder().serviceIdBytes(serviceIdBinary).build()).collect(Collectors.toList())); - for (DecryptedMember member : addedMembersByRequestApproval) { - builder.addPromoteRequestingMembers(DecryptedApproveMember.newBuilder() - .setAciBytes(member.getAciBytes()) - .setRole(member.getRole())); - } + builder.newBannedMembers(newBannedMemberServiceIds.stream() + .map(serviceIdBinary -> { + DecryptedBannedMember.Builder newBannedBuilder = new DecryptedBannedMember.Builder().serviceIdBytes(serviceIdBinary); + DecryptedBannedMember bannedMember = bannedMembersServiceIdMap.get(serviceIdBinary); + if (bannedMember != null) { + newBannedBuilder.timestamp(bannedMember.timestamp); + } - if (!fromState.getInviteLinkPassword().equals(toState.getInviteLinkPassword())) { - builder.setNewInviteLinkPassword(toState.getInviteLinkPassword()); - } - - for (ByteString serviceIdBinary : removedBannedMemberServiceIds) { - builder.addDeleteBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBytes(serviceIdBinary).build()); - } - - for (ByteString serviceIdBinary : newBannedMemberServiceIds) { - DecryptedBannedMember.Builder newBannedBuilder = DecryptedBannedMember.newBuilder().setServiceIdBytes(serviceIdBinary); - DecryptedBannedMember bannedMember = bannedMembersServiceIdMap.get(serviceIdBinary); - if (bannedMember != null) { - newBannedBuilder.setTimestamp(bannedMember.getTimestamp()); - } - - builder.addNewBannedMembers(newBannedBuilder); - } + return newBannedBuilder.build(); + }) + .collect(Collectors.toList())); return builder.build(); } @@ -168,7 +175,7 @@ public final class GroupChangeReconstruct { private static Map mapByAci(List membersList) { Map map = new LinkedHashMap<>(membersList.size()); for (DecryptedMember member : membersList) { - map.put(member.getAciBytes(), member); + map.put(member.aciBytes, member); } return map; } @@ -176,7 +183,7 @@ public final class GroupChangeReconstruct { private static Map bannedServiceIdMap(List membersList) { Map map = new LinkedHashMap<>(membersList.size()); for (DecryptedBannedMember member : membersList) { - map.put(member.getServiceIdBytes(), member); + map.put(member.serviceIdBytes, member); } return map; } @@ -184,7 +191,7 @@ public final class GroupChangeReconstruct { private static Set intersectByAci(Collection members, Set acis) { Set result = new LinkedHashSet<>(members.size()); for (DecryptedMember member : members) { - if (acis.contains(member.getAciBytes())) + if (acis.contains(member.aciBytes)) result.add(member); } return result; @@ -193,16 +200,16 @@ public final class GroupChangeReconstruct { private static Set intersectPendingByServiceId(Collection members, Set serviceIds) { Set result = new LinkedHashSet<>(members.size()); for (DecryptedPendingMember member : members) { - if (serviceIds.contains(member.getServiceIdBytes())) + if (serviceIds.contains(member.serviceIdBytes)) result.add(member); } return result; } - + private static Set intersectRequestingByAci(Collection members, Set acis) { Set result = new LinkedHashSet<>(members.size()); for (DecryptedRequestingMember member : members) { - if (acis.contains(member.getAciBytes())) + if (acis.contains(member.aciBytes)) result.add(member); } return result; @@ -211,7 +218,7 @@ public final class GroupChangeReconstruct { private static Set pendingMembersToSetOfServiceIds(Collection pendingMembers) { Set serviceIds = new LinkedHashSet<>(pendingMembers.size()); for (DecryptedPendingMember pendingMember : pendingMembers) { - serviceIds.add(pendingMember.getServiceIdBytes()); + serviceIds.add(pendingMember.serviceIdBytes); } return serviceIds; } @@ -219,7 +226,7 @@ public final class GroupChangeReconstruct { private static Set requestingMembersToSetOfAcis(Collection requestingMembers) { Set acis = new LinkedHashSet<>(requestingMembers.size()); for (DecryptedRequestingMember requestingMember : requestingMembers) { - acis.add(requestingMember.getAciBytes()); + acis.add(requestingMember.aciBytes); } return acis; } @@ -227,7 +234,7 @@ public final class GroupChangeReconstruct { private static Set membersToSetOfAcis(Collection members) { Set acis = new LinkedHashSet<>(members.size()); for (DecryptedMember member : members) { - acis.add(member.getAciBytes()); + acis.add(member.aciBytes); } return acis; } @@ -235,7 +242,7 @@ public final class GroupChangeReconstruct { private static Set bannedMembersToSetOfServiceIds(Collection bannedMembers) { Set serviceIds = new LinkedHashSet<>(bannedMembers.size()); for (DecryptedBannedMember bannedMember : bannedMembers) { - serviceIds.add(bannedMember.getServiceIdBytes()); + serviceIds.add(bannedMember.serviceIdBytes); } return serviceIds; } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil.java index 73891a9826..18f079c204 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.signal.storageservice.protos.groups.GroupChange; import org.signal.storageservice.protos.groups.local.DecryptedApproveMember; import org.signal.storageservice.protos.groups.local.DecryptedBannedMember; @@ -16,6 +14,8 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; import java.util.HashMap; import java.util.List; +import okio.ByteString; + public final class GroupChangeUtil { private GroupChangeUtil() { @@ -25,28 +25,28 @@ public final class GroupChangeUtil { * True iff there are no change actions. */ public static boolean changeIsEmpty(GroupChange.Actions change) { - return change.getAddMembersCount() == 0 && // field 3 - change.getDeleteMembersCount() == 0 && // field 4 - change.getModifyMemberRolesCount() == 0 && // field 5 - change.getModifyMemberProfileKeysCount() == 0 && // field 6 - change.getAddPendingMembersCount() == 0 && // field 7 - change.getDeletePendingMembersCount() == 0 && // field 8 - change.getPromotePendingMembersCount() == 0 && // field 9 - !change.hasModifyTitle() && // field 10 - !change.hasModifyAvatar() && // field 11 - !change.hasModifyDisappearingMessagesTimer() && // field 12 - !change.hasModifyAttributesAccess() && // field 13 - !change.hasModifyMemberAccess() && // field 14 - !change.hasModifyAddFromInviteLinkAccess() && // field 15 - change.getAddRequestingMembersCount() == 0 && // field 16 - change.getDeleteRequestingMembersCount() == 0 && // field 17 - change.getPromoteRequestingMembersCount() == 0 && // field 18 - !change.hasModifyInviteLinkPassword() && // field 19 - !change.hasModifyDescription() && // field 20 - !change.hasModifyAnnouncementsOnly() && // field 21 - change.getAddBannedMembersCount() == 0 && // field 22 - change.getDeleteBannedMembersCount() == 0 && // field 23 - change.getPromotePendingPniAciMembersCount() == 0; // field 24 + return change.addMembers.size() == 0 && // field 3 + change.deleteMembers.size() == 0 && // field 4 + change.modifyMemberRoles.size() == 0 && // field 5 + change.modifyMemberProfileKeys.size() == 0 && // field 6 + change.addPendingMembers.size() == 0 && // field 7 + change.deletePendingMembers.size() == 0 && // field 8 + change.promotePendingMembers.size() == 0 && // field 9 + change.modifyTitle == null && // field 10 + change.modifyAvatar == null && // field 11 + change.modifyDisappearingMessagesTimer == null && // field 12 + change.modifyAttributesAccess == null && // field 13 + change.modifyMemberAccess == null && // field 14 + change.modifyAddFromInviteLinkAccess == null && // field 15 + change.addRequestingMembers.size() == 0 && // field 16 + change.deleteRequestingMembers.size() == 0 && // field 17 + change.promoteRequestingMembers.size() == 0 && // field 18 + change.modifyInviteLinkPassword == null && // field 19 + change.modifyDescription == null && // field 20 + change.modifyAnnouncementsOnly == null && // field 21 + change.addBannedMembers.size() == 0 && // field 22 + change.deleteBannedMembers.size() == 0 && // field 23 + change.promotePendingPniAciMembers.size() == 0; // field 24 } /** @@ -70,7 +70,7 @@ public final class GroupChangeUtil { DecryptedGroupChange conflictingChange, GroupChange.Actions encryptedChange) { - GroupChange.Actions.Builder result = GroupChange.Actions.newBuilder(encryptedChange); + GroupChange.Actions.Builder result = encryptedChange.newBuilder(); resolveConflict(groupState, conflictingChange, new GroupChangeActionsBuilderChangeSetModifier(result)); @@ -96,7 +96,7 @@ public final class GroupChangeUtil { public static DecryptedGroupChange.Builder resolveConflict(DecryptedGroup groupState, DecryptedGroupChange conflictingChange) { - DecryptedGroupChange.Builder result = DecryptedGroupChange.newBuilder(conflictingChange); + DecryptedGroupChange.Builder result = conflictingChange.newBuilder(); resolveConflict(groupState, conflictingChange, new DecryptedGroupChangeActionsBuilderChangeSetModifier(result)); @@ -107,25 +107,25 @@ public final class GroupChangeUtil { DecryptedGroupChange conflictingChange, ChangeSetModifier changeSetModifier) { - HashMap fullMembersByUuid = new HashMap<>(groupState.getMembersCount()); - HashMap pendingMembersByServiceId = new HashMap<>(groupState.getPendingMembersCount()); - HashMap requestingMembersByUuid = new HashMap<>(groupState.getMembersCount()); - HashMap bannedMembersByServiceId = new HashMap<>(groupState.getBannedMembersCount()); + HashMap fullMembersByUuid = new HashMap<>(groupState.members.size()); + HashMap pendingMembersByServiceId = new HashMap<>(groupState.pendingMembers.size()); + HashMap requestingMembersByUuid = new HashMap<>(groupState.members.size()); + HashMap bannedMembersByServiceId = new HashMap<>(groupState.bannedMembers.size()); - for (DecryptedMember member : groupState.getMembersList()) { - fullMembersByUuid.put(member.getAciBytes(), member); + for (DecryptedMember member : groupState.members) { + fullMembersByUuid.put(member.aciBytes, member); } - for (DecryptedPendingMember member : groupState.getPendingMembersList()) { - pendingMembersByServiceId.put(member.getServiceIdBytes(), member); + for (DecryptedPendingMember member : groupState.pendingMembers) { + pendingMembersByServiceId.put(member.serviceIdBytes, member); } - for (DecryptedRequestingMember member : groupState.getRequestingMembersList()) { - requestingMembersByUuid.put(member.getAciBytes(), member); + for (DecryptedRequestingMember member : groupState.requestingMembers) { + requestingMembersByUuid.put(member.aciBytes, member); } - for (DecryptedBannedMember member : groupState.getBannedMembersList()) { - bannedMembersByServiceId.put(member.getServiceIdBytes(), member); + for (DecryptedBannedMember member : groupState.bannedMembers) { + bannedMembersByServiceId.put(member.serviceIdBytes, member); } resolveField3AddMembers (conflictingChange, changeSetModifier, fullMembersByUuid, pendingMembersByServiceId); @@ -152,21 +152,21 @@ public final class GroupChangeUtil { } private static void resolveField3AddMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap fullMembersByUuid, HashMap pendingMembersByServiceId) { - List newMembersList = conflictingChange.getNewMembersList(); + List newMembersList = conflictingChange.newMembers; for (int i = newMembersList.size() - 1; i >= 0; i--) { DecryptedMember member = newMembersList.get(i); - if (fullMembersByUuid.containsKey(member.getAciBytes())) { + if (fullMembersByUuid.containsKey(member.aciBytes)) { result.removeAddMembers(i); - } else if (pendingMembersByServiceId.containsKey(member.getAciBytes()) || pendingMembersByServiceId.containsKey(member.getPniBytes())) { + } else if (pendingMembersByServiceId.containsKey(member.aciBytes) || pendingMembersByServiceId.containsKey(member.pniBytes)) { result.moveAddToPromote(i); } } } private static void resolveField4DeleteMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap fullMembersByUuid) { - List deletedMembersList = conflictingChange.getDeleteMembersList(); + List deletedMembersList = conflictingChange.deleteMembers; for (int i = deletedMembersList.size() - 1; i >= 0; i--) { ByteString member = deletedMembersList.get(i); @@ -178,112 +178,112 @@ public final class GroupChangeUtil { } private static void resolveField5ModifyMemberRoles(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap fullMembersByUuid) { - List modifyRolesList = conflictingChange.getModifyMemberRolesList(); + List modifyRolesList = conflictingChange.modifyMemberRoles; for (int i = modifyRolesList.size() - 1; i >= 0; i--) { DecryptedModifyMemberRole modifyRoleAction = modifyRolesList.get(i); - DecryptedMember memberInGroup = fullMembersByUuid.get(modifyRoleAction.getAciBytes()); + DecryptedMember memberInGroup = fullMembersByUuid.get(modifyRoleAction.aciBytes); - if (memberInGroup == null || memberInGroup.getRole() == modifyRoleAction.getRole()) { + if (memberInGroup == null || memberInGroup.role == modifyRoleAction.role) { result.removeModifyMemberRoles(i); } } } private static void resolveField6ModifyProfileKeys(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap fullMembersByUuid) { - List modifyProfileKeysList = conflictingChange.getModifiedProfileKeysList(); + List modifyProfileKeysList = conflictingChange.modifiedProfileKeys; for (int i = modifyProfileKeysList.size() - 1; i >= 0; i--) { DecryptedMember member = modifyProfileKeysList.get(i); - DecryptedMember memberInGroup = fullMembersByUuid.get(member.getAciBytes()); + DecryptedMember memberInGroup = fullMembersByUuid.get(member.aciBytes); - if (memberInGroup == null || member.getProfileKey().equals(memberInGroup.getProfileKey())) { + if (memberInGroup == null || member.profileKey.equals(memberInGroup.profileKey)) { result.removeModifyMemberProfileKeys(i); } } } private static void resolveField7AddPendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap fullMembersByUuid, HashMap pendingMembersByServiceId) { - List newPendingMembersList = conflictingChange.getNewPendingMembersList(); + List newPendingMembersList = conflictingChange.newPendingMembers; for (int i = newPendingMembersList.size() - 1; i >= 0; i--) { DecryptedPendingMember member = newPendingMembersList.get(i); - if (fullMembersByUuid.containsKey(member.getServiceIdBytes()) || pendingMembersByServiceId.containsKey(member.getServiceIdBytes())) { + if (fullMembersByUuid.containsKey(member.serviceIdBytes) || pendingMembersByServiceId.containsKey(member.serviceIdBytes)) { result.removeAddPendingMembers(i); } } } private static void resolveField8DeletePendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap pendingMembersByServiceId) { - List deletePendingMembersList = conflictingChange.getDeletePendingMembersList(); + List deletePendingMembersList = conflictingChange.deletePendingMembers; for (int i = deletePendingMembersList.size() - 1; i >= 0; i--) { DecryptedPendingMemberRemoval member = deletePendingMembersList.get(i); - if (!pendingMembersByServiceId.containsKey(member.getServiceIdBytes())) { + if (!pendingMembersByServiceId.containsKey(member.serviceIdBytes)) { result.removeDeletePendingMembers(i); } } } private static void resolveField9PromotePendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap pendingMembersByServiceId) { - List promotePendingMembersList = conflictingChange.getPromotePendingMembersList(); + List promotePendingMembersList = conflictingChange.promotePendingMembers; for (int i = promotePendingMembersList.size() - 1; i >= 0; i--) { DecryptedMember member = promotePendingMembersList.get(i); - if (!pendingMembersByServiceId.containsKey(member.getAciBytes()) && !pendingMembersByServiceId.containsKey(member.getPniBytes())) { + if (!pendingMembersByServiceId.containsKey(member.aciBytes) && !pendingMembersByServiceId.containsKey(member.pniBytes)) { result.removePromotePendingMembers(i); } } } private static void resolveField10ModifyTitle(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.hasNewTitle() && conflictingChange.getNewTitle().getValue().equals(groupState.getTitle())) { + if (conflictingChange.newTitle != null && conflictingChange.newTitle.value_.equals(groupState.title)) { result.clearModifyTitle(); } } private static void resolveField11ModifyAvatar(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.hasNewAvatar() && conflictingChange.getNewAvatar().getValue().equals(groupState.getAvatar())) { + if (conflictingChange.newAvatar != null && conflictingChange.newAvatar.value_.equals(groupState.avatar)) { result.clearModifyAvatar(); } } private static void resolveField12modifyDisappearingMessagesTimer(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.hasNewTimer() && conflictingChange.getNewTimer().getDuration() == groupState.getDisappearingMessagesTimer().getDuration()) { + if (groupState.disappearingMessagesTimer != null && conflictingChange.newTimer != null && conflictingChange.newTimer.duration == groupState.disappearingMessagesTimer.duration) { result.clearModifyDisappearingMessagesTimer(); } } private static void resolveField13modifyAttributesAccess(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.getNewAttributeAccess() == groupState.getAccessControl().getAttributes()) { + if (groupState.accessControl != null && conflictingChange.newAttributeAccess == groupState.accessControl.attributes) { result.clearModifyAttributesAccess(); } } private static void resolveField14modifyAttributesAccess(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.getNewMemberAccess() == groupState.getAccessControl().getMembers()) { + if (groupState.accessControl != null && conflictingChange.newMemberAccess == groupState.accessControl.members) { result.clearModifyMemberAccess(); } } private static void resolveField15modifyAddFromInviteLinkAccess(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.getNewInviteLinkAccess() == groupState.getAccessControl().getAddFromInviteLink()) { + if (groupState.accessControl != null && conflictingChange.newInviteLinkAccess == groupState.accessControl.addFromInviteLink) { result.clearModifyAddFromInviteLinkAccess(); } } private static void resolveField16AddRequestingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap fullMembersByUuid, HashMap pendingMembersByServiceId) { - List newMembersList = conflictingChange.getNewRequestingMembersList(); + List newMembersList = conflictingChange.newRequestingMembers; for (int i = newMembersList.size() - 1; i >= 0; i--) { DecryptedRequestingMember member = newMembersList.get(i); - if (fullMembersByUuid.containsKey(member.getAciBytes())) { + if (fullMembersByUuid.containsKey(member.aciBytes)) { result.removeAddRequestingMembers(i); - } else if (pendingMembersByServiceId.containsKey(member.getAciBytes())) { + } else if (pendingMembersByServiceId.containsKey(member.aciBytes)) { result.moveAddRequestingMembersToPromote(i); } } @@ -293,7 +293,7 @@ public final class GroupChangeUtil { ChangeSetModifier result, HashMap requestingMembers) { - List deletedMembersList = conflictingChange.getDeleteRequestingMembersList(); + List deletedMembersList = conflictingChange.deleteRequestingMembers; for (int i = deletedMembersList.size() - 1; i >= 0; i--) { ByteString member = deletedMembersList.get(i); @@ -308,60 +308,60 @@ public final class GroupChangeUtil { ChangeSetModifier result, HashMap requestingMembersByUuid) { - List promoteRequestingMembersList = conflictingChange.getPromoteRequestingMembersList(); + List promoteRequestingMembersList = conflictingChange.promoteRequestingMembers; for (int i = promoteRequestingMembersList.size() - 1; i >= 0; i--) { DecryptedApproveMember member = promoteRequestingMembersList.get(i); - if (!requestingMembersByUuid.containsKey(member.getAciBytes())) { + if (!requestingMembersByUuid.containsKey(member.aciBytes)) { result.removePromoteRequestingMembers(i); } } } private static void resolveField20ModifyDescription(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.hasNewDescription() && conflictingChange.getNewDescription().getValue().equals(groupState.getDescription())) { + if (conflictingChange.newDescription != null && conflictingChange.newDescription.value_.equals(groupState.description)) { result.clearModifyDescription(); } } private static void resolveField21ModifyAnnouncementsOnly(DecryptedGroup groupState, DecryptedGroupChange conflictingChange, ChangeSetModifier result) { - if (conflictingChange.getNewIsAnnouncementGroup().equals(groupState.getIsAnnouncementGroup())) { + if (conflictingChange.newIsAnnouncementGroup.equals(groupState.isAnnouncementGroup)) { result.clearModifyAnnouncementsOnly(); } } private static void resolveField22AddBannedMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap bannedMembersByServiceId) { - List newBannedMembersList = conflictingChange.getNewBannedMembersList(); + List newBannedMembersList = conflictingChange.newBannedMembers; for (int i = newBannedMembersList.size() - 1; i >= 0; i--) { DecryptedBannedMember member = newBannedMembersList.get(i); - if (bannedMembersByServiceId.containsKey(member.getServiceIdBytes())) { + if (bannedMembersByServiceId.containsKey(member.serviceIdBytes)) { result.removeAddBannedMembers(i); } } } private static void resolveField23DeleteBannedMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap bannedMembersByServiceId) { - List deleteBannedMembersList = conflictingChange.getDeleteBannedMembersList(); + List deleteBannedMembersList = conflictingChange.deleteBannedMembers; for (int i = deleteBannedMembersList.size() - 1; i >= 0; i--) { DecryptedBannedMember member = deleteBannedMembersList.get(i); - if (!bannedMembersByServiceId.containsKey(member.getServiceIdBytes())) { + if (!bannedMembersByServiceId.containsKey(member.serviceIdBytes)) { result.removeDeleteBannedMembers(i); } } } private static void resolveField24PromotePendingPniAciMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap fullMembersByAci) { - List promotePendingPniAciMembersList = conflictingChange.getPromotePendingPniAciMembersList(); + List promotePendingPniAciMembersList = conflictingChange.promotePendingPniAciMembers; for (int i = promotePendingPniAciMembersList.size() - 1; i >= 0; i--) { DecryptedMember member = promotePendingPniAciMembersList.get(i); - if (fullMembersByAci.containsKey(member.getAciBytes())) { + if (fullMembersByAci.containsKey(member.aciBytes)) { result.removePromotePendingPniAciMembers(i); } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java index ecbd372483..42b87b7946 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.VerificationFailedException; import org.signal.libsignal.zkgroup.auth.AuthCredentialPresentation; @@ -34,6 +32,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import okio.ByteString; + public class GroupsV2Api { private final PushServiceSocket socket; @@ -79,8 +79,8 @@ public class GroupsV2Api { if (newGroup.getAvatar().isPresent()) { String cdnKey = uploadAvatar(newGroup.getAvatar().get(), newGroup.getGroupSecretParams(), authorization); - group = Group.newBuilder(group) - .setAvatar(cdnKey) + group = group.newBuilder() + .avatar(cdnKey) .build(); } @@ -114,12 +114,12 @@ public class GroupsV2Api { throws IOException, InvalidGroupStateException, VerificationFailedException { PushServiceSocket.GroupHistory group = socket.getGroupsV2GroupHistory(fromRevision, authorization, GroupsV2Operations.HIGHEST_KNOWN_EPOCH, includeFirstState); - List result = new ArrayList<>(group.getGroupChanges().getGroupChangesList().size()); + List result = new ArrayList<>(group.getGroupChanges().groupChanges.size()); GroupsV2Operations.GroupOperations groupOperations = groupsOperations.forGroup(groupSecretParams); - for (GroupChanges.GroupChangeState change : group.getGroupChanges().getGroupChangesList()) { - Optional decryptedGroup = change.hasGroupState() ? Optional.of(groupOperations.decryptGroup(change.getGroupState())) : Optional.empty(); - Optional decryptedChange = change.hasGroupChange() ? groupOperations.decryptChange(change.getGroupChange(), false) : Optional.empty(); + for (GroupChanges.GroupChangeState change : group.getGroupChanges().groupChanges) { + Optional decryptedGroup = change.groupState != null ? Optional.of(groupOperations.decryptGroup(change.groupState)) : Optional.empty(); + Optional decryptedChange = change.groupChange != null ? groupOperations.decryptChange(change.groupChange, false) : Optional.empty(); result.add(new DecryptedGroupHistoryEntry(decryptedGroup, decryptedChange)); } @@ -151,14 +151,14 @@ public class GroupsV2Api { byte[] cipherText; try { - cipherText = new ClientZkGroupCipher(groupSecretParams).encryptBlob(GroupAttributeBlob.newBuilder().setAvatar(ByteString.copyFrom(avatar)).build().toByteArray()); + cipherText = new ClientZkGroupCipher(groupSecretParams).encryptBlob(new GroupAttributeBlob.Builder().avatar(ByteString.of(avatar)).build().encode()); } catch (VerificationFailedException e) { throw new AssertionError(e); } socket.uploadGroupV2Avatar(cipherText, form); - return form.getKey(); + return form.key; } public GroupChange patchGroup(GroupChange.Actions groupChange, diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java index 7e23110fcf..6bc345189b 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java @@ -1,8 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.libsignal.protocol.logging.Log; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.NotarySignature; @@ -39,11 +36,12 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; import org.signal.storageservice.protos.groups.local.DecryptedString; import org.signal.storageservice.protos.groups.local.DecryptedTimer; import org.signal.storageservice.protos.groups.local.EnabledState; +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.util.UuidUtil; +import java.io.IOException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; @@ -55,6 +53,8 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import okio.ByteString; + /** * Contains operations to create, modify and validate groups and group changes. */ @@ -103,27 +103,34 @@ public final class GroupsV2Operations { final GroupOperations groupOperations = forGroup(groupSecretParams); - Group.Builder group = Group.newBuilder() - .setRevision(0) - .setPublicKey(ByteString.copyFrom(groupSecretParams.getPublicParams().serialize())) - .setTitle(groupOperations.encryptTitle(title)) - .setDisappearingMessagesTimer(groupOperations.encryptTimer(disappearingMessageTimerSeconds)) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.MEMBER) - .setMembers(AccessControl.AccessRequired.MEMBER)); + Group.Builder group = new Group.Builder() + .revision(0) + .publicKey(ByteString.of(groupSecretParams.getPublicParams().serialize())) + .title(groupOperations.encryptTitle(title)) + .disappearingMessagesTimer(groupOperations.encryptTimer(disappearingMessageTimerSeconds)) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.MEMBER) + .members(AccessControl.AccessRequired.MEMBER) + .build()); - group.addMembers(groupOperations.member(self.requireExpiringProfileKeyCredential(), Member.Role.ADMINISTRATOR)); + List groupMembers = new ArrayList<>(); + List groupPendingMembers = new ArrayList<>(); + + groupMembers.add(groupOperations.member(self.requireExpiringProfileKeyCredential(), Member.Role.ADMINISTRATOR).build()); for (GroupCandidate credential : members) { ExpiringProfileKeyCredential expiringProfileKeyCredential = credential.getExpiringProfileKeyCredential().orElse(null); if (expiringProfileKeyCredential != null) { - group.addMembers(groupOperations.member(expiringProfileKeyCredential, memberRole)); + groupMembers.add(groupOperations.member(expiringProfileKeyCredential, memberRole).build()); } else { - group.addPendingMembers(groupOperations.invitee(credential.getServiceId(), memberRole)); + groupPendingMembers.add(groupOperations.invitee(credential.getServiceId(), memberRole).build()); } } + group.members(groupMembers) + .pendingMembers(groupPendingMembers); + return new NewGroup(groupSecretParams, group.build(), avatar); } @@ -153,17 +160,15 @@ public final class GroupsV2Operations { } public GroupChange.Actions.Builder createModifyGroupTitle(final String title) { - return GroupChange.Actions.newBuilder().setModifyTitle(GroupChange.Actions.ModifyTitleAction - .newBuilder() - .setTitle(encryptTitle(title))); + return new GroupChange.Actions.Builder().modifyTitle(new GroupChange.Actions.ModifyTitleAction.Builder().title(encryptTitle(title)).build()); } public GroupChange.Actions.ModifyDescriptionAction.Builder createModifyGroupDescriptionAction(final String description) { - return GroupChange.Actions.ModifyDescriptionAction.newBuilder().setDescription(encryptDescription(description)); + return new GroupChange.Actions.ModifyDescriptionAction.Builder().description(encryptDescription(description)); } public GroupChange.Actions.Builder createModifyGroupDescription(final String description) { - return GroupChange.Actions.newBuilder().setModifyDescription(createModifyGroupDescriptionAction(description)); + return new GroupChange.Actions.Builder().modifyDescription(createModifyGroupDescriptionAction(description).build()); } public GroupChange.Actions.Builder createModifyGroupMembershipChange(Set membersToAdd, Set bannedMembers, ACI selfAci) { @@ -171,241 +176,218 @@ public final class GroupsV2Operations { Set membersToUnban = membersToAdd.stream().map(GroupCandidate::getServiceId).filter(bannedMembers::contains).collect(Collectors.toSet()); - GroupChange.Actions.Builder actions = membersToUnban.isEmpty() ? GroupChange.Actions.newBuilder() + GroupChange.Actions.Builder actions = membersToUnban.isEmpty() ? new GroupChange.Actions.Builder() : createUnbanServiceIdsChange(membersToUnban); + List addGroupMembers = new ArrayList<>(actions.addMembers); + List addGroupPendingMembers = new ArrayList<>(actions.addPendingMembers); for (GroupCandidate credential : membersToAdd) { Member.Role newMemberRole = Member.Role.DEFAULT; ExpiringProfileKeyCredential expiringProfileKeyCredential = credential.getExpiringProfileKeyCredential().orElse(null); if (expiringProfileKeyCredential != null) { - actions.addAddMembers(GroupChange.Actions.AddMemberAction - .newBuilder() - .setAdded(groupOperations.member(expiringProfileKeyCredential, newMemberRole))); + addGroupMembers.add(new GroupChange.Actions.AddMemberAction.Builder().added(groupOperations.member(expiringProfileKeyCredential, newMemberRole).build()).build()); } else { - actions.addAddPendingMembers(GroupChange.Actions.AddPendingMemberAction - .newBuilder() - .setAdded(groupOperations.invitee(credential.getServiceId(), newMemberRole) - .setAddedByUserId(encryptServiceId(selfAci)))); + addGroupPendingMembers.add(new GroupChange.Actions.AddPendingMemberAction.Builder().added(groupOperations.invitee(credential.getServiceId(), newMemberRole) + .addedByUserId(encryptServiceId(selfAci)) + .build()) + .build()); } } - return actions; + return actions.addMembers(addGroupMembers) + .addPendingMembers(addGroupPendingMembers); } public GroupChange.Actions.Builder createGroupJoinRequest(ExpiringProfileKeyCredential expiringProfileKeyCredential) { GroupOperations groupOperations = forGroup(groupSecretParams); - GroupChange.Actions.Builder actions = GroupChange.Actions.newBuilder(); + GroupChange.Actions.Builder actions = new GroupChange.Actions.Builder(); - actions.addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction - .newBuilder() - .setAdded(groupOperations.requestingMember(expiringProfileKeyCredential))); + actions.addRequestingMembers = Collections.singletonList(new GroupChange.Actions.AddRequestingMemberAction.Builder().added(groupOperations.requestingMember(expiringProfileKeyCredential).build()).build()); return actions; } public GroupChange.Actions.Builder createGroupJoinDirect(ExpiringProfileKeyCredential expiringProfileKeyCredential) { GroupOperations groupOperations = forGroup(groupSecretParams); - GroupChange.Actions.Builder actions = GroupChange.Actions.newBuilder(); + GroupChange.Actions.Builder actions = new GroupChange.Actions.Builder(); - actions.addAddMembers(GroupChange.Actions.AddMemberAction - .newBuilder() - .setAdded(groupOperations.member(expiringProfileKeyCredential, Member.Role.DEFAULT))); + actions.addMembers = Collections.singletonList(new GroupChange.Actions.AddMemberAction.Builder().added(groupOperations.member(expiringProfileKeyCredential, Member.Role.DEFAULT).build()).build()); return actions; } public GroupChange.Actions.Builder createRefuseGroupJoinRequest(Set requestsToRemove, boolean alsoBan, List bannedMembers) { GroupChange.Actions.Builder actions = alsoBan ? createBanServiceIdsChange(requestsToRemove, false, bannedMembers) - : GroupChange.Actions.newBuilder(); + : new GroupChange.Actions.Builder(); + List deleteRequestingMemberActions = new ArrayList<>(actions.deleteRequestingMembers); for (ServiceId serviceId : requestsToRemove) { if (serviceId instanceof ACI) { - actions.addDeleteRequestingMembers(GroupChange.Actions.DeleteRequestingMemberAction - .newBuilder() - .setDeletedUserId(encryptServiceId(serviceId))); + deleteRequestingMemberActions.add(new GroupChange.Actions.DeleteRequestingMemberAction.Builder().deletedUserId(encryptServiceId(serviceId)).build()); } } - - return actions; + return actions.deleteRequestingMembers(deleteRequestingMemberActions); } public GroupChange.Actions.Builder createApproveGroupJoinRequest(Set requestsToApprove) { - GroupChange.Actions.Builder actions = GroupChange.Actions.newBuilder(); + GroupChange.Actions.Builder actions = new GroupChange.Actions.Builder(); - for (UUID uuid : requestsToApprove) { - actions.addPromoteRequestingMembers(GroupChange.Actions.PromoteRequestingMemberAction - .newBuilder() - .setRole(Member.Role.DEFAULT) - .setUserId(encryptServiceId(ACI.from(uuid)))); - } + actions.promoteRequestingMembers = requestsToApprove.stream() + .map(uuid -> new GroupChange.Actions.PromoteRequestingMemberAction.Builder().role(Member.Role.DEFAULT) + .userId(encryptServiceId(ACI.from(uuid))) + .build()) + .collect(Collectors.toList()); return actions; } public GroupChange.Actions.Builder createRemoveMembersChange(final Set membersToRemove, boolean alsoBan, List bannedMembers) { GroupChange.Actions.Builder actions = alsoBan ? createBanServiceIdsChange(membersToRemove, false, bannedMembers) - : GroupChange.Actions.newBuilder(); + : new GroupChange.Actions.Builder(); + List deleteMemberActions = new ArrayList<>(actions.deleteMembers); for (ACI remove: membersToRemove) { - actions.addDeleteMembers(GroupChange.Actions.DeleteMemberAction - .newBuilder() - .setDeletedUserId(encryptServiceId(remove))); + deleteMemberActions.add(new GroupChange.Actions.DeleteMemberAction.Builder().deletedUserId(encryptServiceId(remove)).build()); } - - return actions; + return actions.deleteMembers(deleteMemberActions); } public GroupChange.Actions.Builder createLeaveAndPromoteMembersToAdmin(ACI self, List membersToMakeAdmin) { GroupChange.Actions.Builder actions = createRemoveMembersChange(Collections.singleton(self), false, Collections.emptyList()); + List modifyMemberRoleActions = new ArrayList<>(actions.modifyMemberRoles); for (UUID member : membersToMakeAdmin) { - actions.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction - .newBuilder() - .setUserId(encryptServiceId(ACI.from(member))) - .setRole(Member.Role.ADMINISTRATOR)); + modifyMemberRoleActions.add(new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encryptServiceId(ACI.from(member))).role(Member.Role.ADMINISTRATOR).build()); } - - return actions; + return actions.modifyMemberRoles(modifyMemberRoleActions); } public GroupChange.Actions.Builder createModifyGroupTimerChange(int timerDurationSeconds) { - return GroupChange.Actions - .newBuilder() - .setModifyDisappearingMessagesTimer(GroupChange.Actions.ModifyDisappearingMessagesTimerAction - .newBuilder() - .setTimer(encryptTimer(timerDurationSeconds))); + return new GroupChange.Actions.Builder() + .modifyDisappearingMessagesTimer(new GroupChange.Actions.ModifyDisappearingMessagesTimerAction.Builder().timer(encryptTimer(timerDurationSeconds)).build()); } public GroupChange.Actions.Builder createUpdateProfileKeyCredentialChange(ExpiringProfileKeyCredential expiringProfileKeyCredential) { ProfileKeyCredentialPresentation presentation = clientZkProfileOperations.createProfileKeyCredentialPresentation(random, groupSecretParams, expiringProfileKeyCredential); - return GroupChange.Actions - .newBuilder() - .addModifyMemberProfileKeys(GroupChange.Actions.ModifyMemberProfileKeyAction - .newBuilder() - .setPresentation(ByteString.copyFrom(presentation.serialize()))); + return new GroupChange.Actions.Builder().modifyMemberProfileKeys(Collections.singletonList( + new GroupChange.Actions.ModifyMemberProfileKeyAction.Builder() + .presentation(ByteString.of(presentation.serialize())) + .build() + )); } public GroupChange.Actions.Builder createAcceptInviteChange(ExpiringProfileKeyCredential credential) { ProfileKeyCredentialPresentation presentation = clientZkProfileOperations.createProfileKeyCredentialPresentation(random, groupSecretParams, credential); - return GroupChange.Actions.newBuilder() - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder() - .setPresentation(ByteString.copyFrom(presentation.serialize()))); + return new GroupChange.Actions.Builder().promotePendingMembers(Collections.singletonList( + new GroupChange.Actions.PromotePendingMemberAction.Builder() + .presentation(ByteString.of(presentation.serialize())) + .build() + )); } public GroupChange.Actions.Builder createAcceptPniInviteChange(ExpiringProfileKeyCredential credential) { - ByteString presentation = ByteString.copyFrom(clientZkProfileOperations.createProfileKeyCredentialPresentation(random, groupSecretParams, credential).serialize()); + ByteString presentation = ByteString.of(clientZkProfileOperations.createProfileKeyCredentialPresentation(random, groupSecretParams, credential).serialize()); - return GroupChange.Actions.newBuilder() - .addPromotePendingPniAciMembers(GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.newBuilder() - .setPresentation(presentation)); + return new GroupChange.Actions.Builder().promotePendingPniAciMembers(Collections.singletonList( + new GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.Builder().presentation(presentation).build() + )); } public GroupChange.Actions.Builder createRemoveInvitationChange(final Set uuidCipherTextsFromInvitesToRemove) { - GroupChange.Actions.Builder builder = GroupChange.Actions - .newBuilder(); + GroupChange.Actions.Builder builder = new GroupChange.Actions.Builder(); - for (UuidCiphertext uuidCipherText: uuidCipherTextsFromInvitesToRemove) { - builder.addDeletePendingMembers(GroupChange.Actions.DeletePendingMemberAction - .newBuilder() - .setDeletedUserId(ByteString.copyFrom(uuidCipherText.serialize()))); - } + builder.deletePendingMembers = uuidCipherTextsFromInvitesToRemove.stream() + .map(uuidCipherText -> new GroupChange.Actions.DeletePendingMemberAction.Builder().deletedUserId(ByteString.of(uuidCipherText.serialize())) + .build()) + .collect(Collectors.toList()); return builder; } public GroupChange.Actions.Builder createModifyGroupLinkPasswordChange(byte[] groupLinkPassword) { - return GroupChange.Actions - .newBuilder() - .setModifyInviteLinkPassword(GroupChange.Actions.ModifyInviteLinkPasswordAction - .newBuilder() - .setInviteLinkPassword(ByteString.copyFrom(groupLinkPassword))); + return new GroupChange.Actions.Builder().modifyInviteLinkPassword( + new GroupChange.Actions.ModifyInviteLinkPasswordAction.Builder().inviteLinkPassword(ByteString.of(groupLinkPassword)).build() + ); } public GroupChange.Actions.Builder createModifyGroupLinkPasswordAndRightsChange(byte[] groupLinkPassword, AccessControl.AccessRequired newRights) { GroupChange.Actions.Builder change = createModifyGroupLinkPasswordChange(groupLinkPassword); - return change.setModifyAddFromInviteLinkAccess(GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - .newBuilder() - .setAddFromInviteLinkAccess(newRights)); + return change.modifyAddFromInviteLinkAccess(new GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.Builder().addFromInviteLinkAccess(newRights).build()); } public GroupChange.Actions.Builder createChangeJoinByLinkRights(AccessControl.AccessRequired newRights) { - return GroupChange.Actions - .newBuilder() - .setModifyAddFromInviteLinkAccess(GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - .newBuilder() - .setAddFromInviteLinkAccess(newRights)); + return new GroupChange.Actions.Builder().modifyAddFromInviteLinkAccess(new GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.Builder().addFromInviteLinkAccess(newRights).build()); } public GroupChange.Actions.Builder createChangeMembershipRights(AccessControl.AccessRequired newRights) { - return GroupChange.Actions - .newBuilder() - .setModifyMemberAccess(GroupChange.Actions.ModifyMembersAccessControlAction - .newBuilder() - .setMembersAccess(newRights)); + return new GroupChange.Actions.Builder().modifyMemberAccess( + new GroupChange.Actions.ModifyMembersAccessControlAction.Builder().membersAccess(newRights).build() + ); } public GroupChange.Actions.Builder createChangeAttributesRights(AccessControl.AccessRequired newRights) { - return GroupChange.Actions - .newBuilder() - .setModifyAttributesAccess(GroupChange.Actions.ModifyAttributesAccessControlAction - .newBuilder() - .setAttributesAccess(newRights)); + return new GroupChange.Actions.Builder().modifyAttributesAccess( + new GroupChange.Actions.ModifyAttributesAccessControlAction.Builder().attributesAccess(newRights).build() + ); } public GroupChange.Actions.Builder createAnnouncementGroupChange(boolean isAnnouncementGroup) { - return GroupChange.Actions - .newBuilder() - .setModifyAnnouncementsOnly(GroupChange.Actions.ModifyAnnouncementsOnlyAction - .newBuilder() - .setAnnouncementsOnly(isAnnouncementGroup)); + return new GroupChange.Actions.Builder().modifyAnnouncementsOnly( + new GroupChange.Actions.ModifyAnnouncementsOnlyAction.Builder().announcementsOnly(isAnnouncementGroup).build() + ); } /** Note that this can only ban ACIs. */ public GroupChange.Actions.Builder createBanServiceIdsChange(Set banServiceIds, boolean rejectJoinRequest, List bannedMembersList) { GroupChange.Actions.Builder builder = rejectJoinRequest ? createRefuseGroupJoinRequest(banServiceIds, false, Collections.emptyList()) - : GroupChange.Actions.newBuilder(); + : new GroupChange.Actions.Builder(); int spacesToFree = bannedMembersList.size() + banServiceIds.size() - maxGroupSize; if (spacesToFree > 0) { List unban = bannedMembersList.stream() - .sorted(Comparator.comparingLong(DecryptedBannedMember::getTimestamp)) + .sorted(Comparator.comparingLong(m -> m.timestamp)) .limit(spacesToFree) - .map(DecryptedBannedMember::getServiceIdBytes) + .map(m -> m.serviceIdBytes) .collect(Collectors.toList()); + List deleteBannedMemberActions = new ArrayList<>(builder.deleteBannedMembers); for (ByteString serviceIdBinary : unban) { - builder.addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encryptServiceId(ServiceId.parseOrThrow(serviceIdBinary.toByteArray())))); + deleteBannedMemberActions.add(new GroupChange.Actions.DeleteBannedMemberAction.Builder().deletedUserId(encryptServiceId(ServiceId.parseOrThrow(serviceIdBinary.toByteArray()))).build()); } + builder.deleteBannedMembers(deleteBannedMemberActions); } + List addBannedMemberActions = new ArrayList<>(builder.addBannedMembers); for (ServiceId banServiceId : banServiceIds) { - builder.addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encryptServiceId(banServiceId)).build())); + addBannedMemberActions.add(new GroupChange.Actions.AddBannedMemberAction.Builder().added(new BannedMember.Builder().userId(encryptServiceId(banServiceId)).build()).build()); } + builder.addBannedMembers(addBannedMemberActions); return builder; } public GroupChange.Actions.Builder createUnbanServiceIdsChange(Set serviceIds) { - GroupChange.Actions.Builder builder = GroupChange.Actions.newBuilder(); + GroupChange.Actions.Builder builder = new GroupChange.Actions.Builder(); - for (ServiceId serviceId : serviceIds) { - builder.addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encryptServiceId(serviceId)).build()); - } + builder.deleteBannedMembers = serviceIds.stream() + .map(serviceId -> new GroupChange.Actions.DeleteBannedMemberAction.Builder().deletedUserId(encryptServiceId(serviceId)).build()) + .collect(Collectors.toList()); return builder; } public GroupChange.Actions.Builder replaceAddMembers(GroupChange.Actions.Builder change, List candidates) throws InvalidInputException { - if (change.getAddMembersCount() != candidates.size()) { + if (change.addMembers.size() != candidates.size()) { throw new InvalidInputException("Replacement candidates not same size as original add"); } - for (int i = 0; i < change.getAddMembersCount(); i++) { - GroupChange.Actions.AddMemberAction original = change.getAddMembers(i); + List addMemberActions = new ArrayList<>(change.addMembers); + for (int i = 0; i < addMemberActions.size(); i++) { + GroupChange.Actions.AddMemberAction original = addMemberActions.get(i); GroupCandidate candidate = candidates.get(i); ExpiringProfileKeyCredential expiringProfileKeyCredential = candidate.getExpiringProfileKeyCredential().orElse(null); @@ -414,69 +396,60 @@ public final class GroupsV2Operations { throw new InvalidInputException("Replacement candidate missing credential"); } - change.setAddMembers(i, - GroupChange.Actions.AddMemberAction.newBuilder() - .setAdded(member(expiringProfileKeyCredential, original.getAdded().getRole()))); + addMemberActions.set(i, new GroupChange.Actions.AddMemberAction.Builder().added(member(expiringProfileKeyCredential, original.added.role).build()).build()); } - return change; + return change.addMembers(addMemberActions); } private Member.Builder member(ExpiringProfileKeyCredential credential, Member.Role role) { ProfileKeyCredentialPresentation presentation = clientZkProfileOperations.createProfileKeyCredentialPresentation(new SecureRandom(), groupSecretParams, credential); - return Member.newBuilder() - .setRole(role) - .setPresentation(ByteString.copyFrom(presentation.serialize())); + return new Member.Builder().role(role) + .presentation(ByteString.of(presentation.serialize())); } private RequestingMember.Builder requestingMember(ExpiringProfileKeyCredential credential) { ProfileKeyCredentialPresentation presentation = clientZkProfileOperations.createProfileKeyCredentialPresentation(new SecureRandom(), groupSecretParams, credential); - return RequestingMember.newBuilder() - .setPresentation(ByteString.copyFrom(presentation.serialize())); + return new RequestingMember.Builder().presentation(ByteString.of(presentation.serialize())); } public PendingMember.Builder invitee(ServiceId serviceId, Member.Role role) { UuidCiphertext uuidCiphertext = clientZkGroupCipher.encrypt(serviceId.getLibSignalServiceId()); - Member member = Member.newBuilder() - .setRole(role) - .setUserId(ByteString.copyFrom(uuidCiphertext.serialize())) - .build(); + Member member = new Member.Builder().role(role) + .userId(ByteString.of(uuidCiphertext.serialize())) + .build(); - return PendingMember.newBuilder() - .setMember(member); + return new PendingMember.Builder().member(member); } public PartialDecryptedGroup partialDecryptGroup(Group group) throws VerificationFailedException, InvalidGroupStateException { - List membersList = group.getMembersList(); - List pendingMembersList = group.getPendingMembersList(); + List membersList = group.members; + List pendingMembersList = group.pendingMembers; List decryptedMembers = new ArrayList<>(membersList.size()); List decryptedPendingMembers = new ArrayList<>(pendingMembersList.size()); for (Member member : membersList) { - ACI memberAci = decryptAci(member.getUserId()); - decryptedMembers.add(DecryptedMember.newBuilder() - .setAciBytes(memberAci.toByteString()) - .setJoinedAtRevision(member.getJoinedAtRevision()) - .build()); - } - - for (PendingMember member : pendingMembersList) { - ServiceId pendingMemberServiceId = decryptServiceIdOrUnknown(member.getMember().getUserId()); - decryptedPendingMembers.add(DecryptedPendingMember.newBuilder() - .setServiceIdBytes(pendingMemberServiceId.toByteString()) + ACI memberAci = decryptAci(member.userId); + decryptedMembers.add(new DecryptedMember.Builder().aciBytes(memberAci.toByteString()) + .joinedAtRevision(member.joinedAtRevision) .build()); } - DecryptedGroup decryptedGroup = DecryptedGroup.newBuilder() - .setRevision(group.getRevision()) - .addAllMembers(decryptedMembers) - .addAllPendingMembers(decryptedPendingMembers) - .build(); + for (PendingMember member : pendingMembersList) { + ServiceId pendingMemberServiceId = decryptServiceIdOrUnknown(member.member.userId); + decryptedPendingMembers.add(new DecryptedPendingMember.Builder().serviceIdBytes(pendingMemberServiceId.toByteString()).build()); + } + + DecryptedGroup decryptedGroup = new DecryptedGroup.Builder() + .revision(group.revision) + .members(decryptedMembers) + .pendingMembers(decryptedPendingMembers) + .build(); return new PartialDecryptedGroup(group, decryptedGroup, GroupsV2Operations.this, groupSecretParams); } @@ -484,13 +457,13 @@ public final class GroupsV2Operations { public DecryptedGroup decryptGroup(Group group) throws VerificationFailedException, InvalidGroupStateException { - List membersList = group.getMembersList(); - List pendingMembersList = group.getPendingMembersList(); - List requestingMembersList = group.getRequestingMembersList(); + List membersList = group.members; + List pendingMembersList = group.pendingMembers; + List requestingMembersList = group.requestingMembers; List decryptedMembers = new ArrayList<>(membersList.size()); List decryptedPendingMembers = new ArrayList<>(pendingMembersList.size()); List decryptedRequestingMembers = new ArrayList<>(requestingMembersList.size()); - List decryptedBannedMembers = new ArrayList<>(group.getBannedMembersCount()); + List decryptedBannedMembers = new ArrayList<>(group.bannedMembers.size()); for (Member member : membersList) { try { @@ -508,24 +481,24 @@ public final class GroupsV2Operations { decryptedRequestingMembers.add(decryptRequestingMember(member)); } - for (BannedMember member : group.getBannedMembersList()) { - decryptedBannedMembers.add(DecryptedBannedMember.newBuilder().setServiceIdBytes(decryptServiceIdToBinary(member.getUserId())).setTimestamp(member.getTimestamp()).build()); + for (BannedMember member : group.bannedMembers) { + decryptedBannedMembers.add(new DecryptedBannedMember.Builder().serviceIdBytes(decryptServiceIdToBinary(member.userId)).timestamp(member.timestamp).build()); } - return DecryptedGroup.newBuilder() - .setTitle(decryptTitle(group.getTitle())) - .setDescription(decryptDescription(group.getDescription())) - .setIsAnnouncementGroup(group.getAnnouncementsOnly() ? EnabledState.ENABLED : EnabledState.DISABLED) - .setAvatar(group.getAvatar()) - .setAccessControl(group.getAccessControl()) - .setRevision(group.getRevision()) - .addAllMembers(decryptedMembers) - .addAllPendingMembers(decryptedPendingMembers) - .addAllRequestingMembers(decryptedRequestingMembers) - .setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(decryptDisappearingMessagesTimer(group.getDisappearingMessagesTimer()))) - .setInviteLinkPassword(group.getInviteLinkPassword()) - .addAllBannedMembers(decryptedBannedMembers) - .build(); + return new DecryptedGroup.Builder() + .title(decryptTitle(group.title)) + .description(decryptDescription(group.description)) + .isAnnouncementGroup(group.announcementsOnly ? EnabledState.ENABLED : EnabledState.DISABLED) + .avatar(group.avatar) + .accessControl(group.accessControl) + .revision(group.revision) + .members(decryptedMembers) + .pendingMembers(decryptedPendingMembers) + .requestingMembers(decryptedRequestingMembers) + .disappearingMessagesTimer(new DecryptedTimer.Builder().duration(decryptDisappearingMessagesTimer(group.disappearingMessagesTimer)).build()) + .inviteLinkPassword(group.inviteLinkPassword) + .bannedMembers(decryptedBannedMembers) + .build(); } /** @@ -537,10 +510,10 @@ public final class GroupsV2Operations { * @return {@link Optional#empty()} if the epoch for the change is higher that this code can decrypt. */ public Optional decryptChange(GroupChange groupChange, boolean verifySignature) - throws InvalidProtocolBufferException, VerificationFailedException, InvalidGroupStateException + throws IOException, VerificationFailedException, InvalidGroupStateException { - if (groupChange.getChangeEpoch() > HIGHEST_KNOWN_EPOCH) { - Log.w(TAG, String.format(Locale.US, "Ignoring change from Epoch %d. Highest known Epoch is %d", groupChange.getChangeEpoch(), HIGHEST_KNOWN_EPOCH)); + if (groupChange.changeEpoch > HIGHEST_KNOWN_EPOCH) { + Log.w(TAG, String.format(Locale.US, "Ignoring change from Epoch %d. Highest known Epoch is %d", groupChange.changeEpoch, HIGHEST_KNOWN_EPOCH)); return Optional.empty(); } @@ -558,286 +531,317 @@ public final class GroupsV2Operations { public DecryptedGroupChange decryptChange(GroupChange.Actions actions, ServiceId source) throws VerificationFailedException, InvalidGroupStateException { - DecryptedGroupChange.Builder builder = DecryptedGroupChange.newBuilder(); + DecryptedGroupChange.Builder builder = new DecryptedGroupChange.Builder(); // Field 1 if (source != null) { - builder.setEditorServiceIdBytes(source.toByteString()); + builder.editorServiceIdBytes(source.toByteString()); } else { - builder.setEditorServiceIdBytes(decryptServiceIdToBinary(actions.getSourceServiceId())); + builder.editorServiceIdBytes(decryptServiceIdToBinary(actions.sourceServiceId)); } // Field 2 - builder.setRevision(actions.getRevision()); + builder.revision(actions.revision); // Field 3 - for (GroupChange.Actions.AddMemberAction addMemberAction : actions.getAddMembersList()) { + List newMembers = new ArrayList<>(actions.addMembers.size()); + for (GroupChange.Actions.AddMemberAction addMemberAction : actions.addMembers) { try { - builder.addNewMembers(decryptMember(addMemberAction.getAdded()).setJoinedAtRevision(actions.getRevision())); + newMembers.add(decryptMember(addMemberAction.added).joinedAtRevision(actions.revision).build()); } catch (InvalidInputException e) { throw new InvalidGroupStateException(e); } } + builder.newMembers(newMembers); // Field 4 - for (GroupChange.Actions.DeleteMemberAction deleteMemberAction : actions.getDeleteMembersList()) { - builder.addDeleteMembers(decryptAciToBinary(deleteMemberAction.getDeletedUserId())); + List deleteMembers = new ArrayList<>(actions.deleteMembers.size()); + for (GroupChange.Actions.DeleteMemberAction deleteMemberAction : actions.deleteMembers) { + deleteMembers.add(decryptAciToBinary(deleteMemberAction.deletedUserId)); } + builder.deleteMembers(deleteMembers); // Field 5 - for (GroupChange.Actions.ModifyMemberRoleAction modifyMemberRoleAction : actions.getModifyMemberRolesList()) { - builder.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder() - .setRole(modifyMemberRoleAction.getRole()) - .setAciBytes(decryptAciToBinary(modifyMemberRoleAction.getUserId()))); + List modifyMemberRoles = new ArrayList<>(actions.modifyMemberRoles.size()); + for (GroupChange.Actions.ModifyMemberRoleAction modifyMemberRoleAction : actions.modifyMemberRoles) { + modifyMemberRoles.add(new DecryptedModifyMemberRole.Builder().role(modifyMemberRoleAction.role) + .aciBytes(decryptAciToBinary(modifyMemberRoleAction.userId)) + .build()); } + builder.modifyMemberRoles(modifyMemberRoles); // Field 6 - for (GroupChange.Actions.ModifyMemberProfileKeyAction modifyMemberProfileKeyAction : actions.getModifyMemberProfileKeysList()) { + List modifiedProfileKeys = new ArrayList<>(actions.modifyMemberProfileKeys.size()); + for (GroupChange.Actions.ModifyMemberProfileKeyAction modifyMemberProfileKeyAction : actions.modifyMemberProfileKeys) { try { ACI aci; ProfileKey profileKey; - if (modifyMemberProfileKeyAction.getUserId().isEmpty() || modifyMemberProfileKeyAction.getProfileKey().isEmpty()) { - ProfileKeyCredentialPresentation presentation = new ProfileKeyCredentialPresentation(modifyMemberProfileKeyAction.getPresentation().toByteArray()); - aci = decryptAci(ByteString.copyFrom(presentation.getUuidCiphertext().serialize())); - profileKey = decryptProfileKey(ByteString.copyFrom(presentation.getProfileKeyCiphertext().serialize()), aci); + if (modifyMemberProfileKeyAction.user_id.size() == 0 || modifyMemberProfileKeyAction.presentation.size() == 0) { + ProfileKeyCredentialPresentation presentation = new ProfileKeyCredentialPresentation(modifyMemberProfileKeyAction.presentation.toByteArray()); + aci = decryptAci(ByteString.of(presentation.getUuidCiphertext().serialize())); + profileKey = decryptProfileKey(ByteString.of(presentation.getProfileKeyCiphertext().serialize()), aci); } else { - aci = decryptAci(modifyMemberProfileKeyAction.getUserId()); - profileKey = decryptProfileKey(modifyMemberProfileKeyAction.getProfileKey(), aci); + aci = decryptAci(modifyMemberProfileKeyAction.user_id); + profileKey = decryptProfileKey(modifyMemberProfileKeyAction.profile_key, aci); } - builder.addModifiedProfileKeys(DecryptedMember.newBuilder() - .setRole(Member.Role.UNKNOWN) - .setJoinedAtRevision(-1) - .setAciBytes(aci.toByteString()) - .setProfileKey(ByteString.copyFrom(profileKey.serialize()))); + modifiedProfileKeys.add(new DecryptedMember.Builder() + .role(Member.Role.UNKNOWN) + .joinedAtRevision(-1) + .aciBytes(aci.toByteString()) + .profileKey(ByteString.of(profileKey.serialize())) + .build()); } catch (InvalidInputException e) { throw new InvalidGroupStateException(e); } } + builder.modifiedProfileKeys(modifiedProfileKeys); // Field 7 - for (GroupChange.Actions.AddPendingMemberAction addPendingMemberAction : actions.getAddPendingMembersList()) { - PendingMember added = addPendingMemberAction.getAdded(); - Member member = added.getMember(); - ByteString serviceIdCipherText = member.getUserId(); + List newPendingMembers = new ArrayList<>(actions.addPendingMembers.size()); + for (GroupChange.Actions.AddPendingMemberAction addPendingMemberAction : actions.addPendingMembers) { + PendingMember added = addPendingMemberAction.added; + Member member = added.member; + ByteString serviceIdCipherText = member.userId; ServiceId serviceId = decryptServiceIdOrUnknown(serviceIdCipherText); - builder.addNewPendingMembers(DecryptedPendingMember.newBuilder() - .setServiceIdBytes(serviceId.toByteString()) - .setServiceIdCipherText(serviceIdCipherText) - .setRole(member.getRole()) - .setAddedByAci(decryptAciToBinary(added.getAddedByUserId())) - .setTimestamp(added.getTimestamp())); + newPendingMembers.add(new DecryptedPendingMember.Builder() + .serviceIdBytes(serviceId.toByteString()) + .serviceIdCipherText(serviceIdCipherText) + .role(member.role) + .addedByAci(decryptAciToBinary(added.addedByUserId)) + .timestamp(added.timestamp) + .build()); } + builder.newPendingMembers(newPendingMembers); // Field 8 - for (GroupChange.Actions.DeletePendingMemberAction deletePendingMemberAction : actions.getDeletePendingMembersList()) { - ByteString serviceIdCipherText = deletePendingMemberAction.getDeletedUserId(); + List deletePendingMembers = new ArrayList<>(actions.deletePendingMembers.size()); + for (GroupChange.Actions.DeletePendingMemberAction deletePendingMemberAction : actions.deletePendingMembers) { + ByteString serviceIdCipherText = deletePendingMemberAction.deletedUserId; ServiceId serviceId = decryptServiceIdOrUnknown(serviceIdCipherText); - builder.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(serviceId.toByteString()) - .setServiceIdCipherText(serviceIdCipherText)); + deletePendingMembers.add(new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(serviceId.toByteString()) + .serviceIdCipherText(serviceIdCipherText) + .build()); } + builder.deletePendingMembers(deletePendingMembers); // Field 9 - for (GroupChange.Actions.PromotePendingMemberAction promotePendingMemberAction : actions.getPromotePendingMembersList()) { + List promotePendingMembers = new ArrayList<>(actions.promotePendingMembers.size()); + for (GroupChange.Actions.PromotePendingMemberAction promotePendingMemberAction : actions.promotePendingMembers) { try { ACI aci; ProfileKey profileKey; - if (promotePendingMemberAction.getUserId().isEmpty() || promotePendingMemberAction.getProfileKey().isEmpty()) { - ProfileKeyCredentialPresentation presentation = new ProfileKeyCredentialPresentation(promotePendingMemberAction.getPresentation().toByteArray()); - aci = decryptAci(ByteString.copyFrom(presentation.getUuidCiphertext().serialize())); - profileKey = decryptProfileKey(ByteString.copyFrom(presentation.getProfileKeyCiphertext().serialize()), aci); + if (promotePendingMemberAction.user_id.size() == 0 || promotePendingMemberAction.profile_key.size() == 0) { + ProfileKeyCredentialPresentation presentation = new ProfileKeyCredentialPresentation(promotePendingMemberAction.presentation.toByteArray()); + aci = decryptAci(ByteString.of(presentation.getUuidCiphertext().serialize())); + profileKey = decryptProfileKey(ByteString.of(presentation.getProfileKeyCiphertext().serialize()), aci); } else { - aci = decryptAci(promotePendingMemberAction.getUserId()); - profileKey = decryptProfileKey(promotePendingMemberAction.getProfileKey(), aci); + aci = decryptAci(promotePendingMemberAction.user_id); + profileKey = decryptProfileKey(promotePendingMemberAction.profile_key, aci); } - builder.addPromotePendingMembers(DecryptedMember.newBuilder() - .setJoinedAtRevision(-1) - .setRole(Member.Role.DEFAULT) - .setAciBytes(aci.toByteString()) - .setProfileKey(ByteString.copyFrom(profileKey.serialize()))); + promotePendingMembers.add(new DecryptedMember.Builder() + .joinedAtRevision(-1) + .role(Member.Role.DEFAULT) + .aciBytes(aci.toByteString()) + .profileKey(ByteString.of(profileKey.serialize())) + .build()); } catch (InvalidInputException e) { throw new InvalidGroupStateException(e); } } + builder.promotePendingMembers(promotePendingMembers); // Field 10 - if (actions.hasModifyTitle()) { - builder.setNewTitle(DecryptedString.newBuilder().setValue(decryptTitle(actions.getModifyTitle().getTitle()))); + if (actions.modifyTitle != null) { + builder.newTitle(new DecryptedString.Builder().value_(decryptTitle(actions.modifyTitle.title)).build()); } // Field 11 - if (actions.hasModifyAvatar()) { - builder.setNewAvatar(DecryptedString.newBuilder().setValue(actions.getModifyAvatar().getAvatar())); + if (actions.modifyAvatar != null) { + builder.newAvatar(new DecryptedString.Builder().value_(actions.modifyAvatar.avatar).build()); } // Field 12 - if (actions.hasModifyDisappearingMessagesTimer()) { - int duration = decryptDisappearingMessagesTimer(actions.getModifyDisappearingMessagesTimer().getTimer()); - builder.setNewTimer(DecryptedTimer.newBuilder().setDuration(duration)); + if (actions.modifyDisappearingMessagesTimer != null) { + int duration = decryptDisappearingMessagesTimer(actions.modifyDisappearingMessagesTimer.timer); + builder.newTimer(new DecryptedTimer.Builder().duration(duration).build()); } // Field 13 - if (actions.hasModifyAttributesAccess()) { - builder.setNewAttributeAccess(actions.getModifyAttributesAccess().getAttributesAccess()); + if (actions.modifyAttributesAccess != null) { + builder.newAttributeAccess(actions.modifyAttributesAccess.attributesAccess); } // Field 14 - if (actions.hasModifyMemberAccess()) { - builder.setNewMemberAccess(actions.getModifyMemberAccess().getMembersAccess()); + if (actions.modifyMemberAccess != null) { + builder.newMemberAccess(actions.modifyMemberAccess.membersAccess); } // Field 15 - if (actions.hasModifyAddFromInviteLinkAccess()) { - builder.setNewInviteLinkAccess(actions.getModifyAddFromInviteLinkAccess().getAddFromInviteLinkAccess()); + if (actions.modifyAddFromInviteLinkAccess != null) { + builder.newInviteLinkAccess(actions.modifyAddFromInviteLinkAccess.addFromInviteLinkAccess); } // Field 16 - for (GroupChange.Actions.AddRequestingMemberAction request : actions.getAddRequestingMembersList()) { - builder.addNewRequestingMembers(decryptRequestingMember(request.getAdded())); + List newRequestingMembers = new ArrayList<>(actions.addRequestingMembers.size()); + for (GroupChange.Actions.AddRequestingMemberAction request : actions.addRequestingMembers) { + newRequestingMembers.add(decryptRequestingMember(request.added)); } + builder.newRequestingMembers(newRequestingMembers); // Field 17 - for (GroupChange.Actions.DeleteRequestingMemberAction delete : actions.getDeleteRequestingMembersList()) { - builder.addDeleteRequestingMembers(decryptServiceIdToBinary(delete.getDeletedUserId())); + List deleteRequestingMembers = new ArrayList<>(actions.deleteRequestingMembers.size()); + for (GroupChange.Actions.DeleteRequestingMemberAction delete : actions.deleteRequestingMembers) { + deleteRequestingMembers.add(decryptServiceIdToBinary(delete.deletedUserId)); } + builder.deleteRequestingMembers(deleteRequestingMembers); // Field 18 - for (GroupChange.Actions.PromoteRequestingMemberAction promote : actions.getPromoteRequestingMembersList()) { - builder.addPromoteRequestingMembers(DecryptedApproveMember.newBuilder().setRole(promote.getRole()).setAciBytes(decryptAciToBinary(promote.getUserId()))); + List promoteRequestingMembers = new ArrayList<>(actions.promoteRequestingMembers.size()); + for (GroupChange.Actions.PromoteRequestingMemberAction promote : actions.promoteRequestingMembers) { + promoteRequestingMembers.add(new DecryptedApproveMember.Builder().role(promote.role).aciBytes(decryptAciToBinary(promote.userId)).build()); } + builder.promoteRequestingMembers(promoteRequestingMembers); // Field 19 - if (actions.hasModifyInviteLinkPassword()) { - builder.setNewInviteLinkPassword(actions.getModifyInviteLinkPassword().getInviteLinkPassword()); + if (actions.modifyInviteLinkPassword != null) { + builder.newInviteLinkPassword(actions.modifyInviteLinkPassword.inviteLinkPassword); } // Field 20 - if (actions.hasModifyDescription()) { - builder.setNewDescription(DecryptedString.newBuilder().setValue(decryptDescription(actions.getModifyDescription().getDescription()))); + if (actions.modifyDescription != null) { + builder.newDescription(new DecryptedString.Builder().value_(decryptDescription(actions.modifyDescription.description)).build()); } // Field 21 - if (actions.hasModifyAnnouncementsOnly()) { - builder.setNewIsAnnouncementGroup(actions.getModifyAnnouncementsOnly().getAnnouncementsOnly() ? EnabledState.ENABLED : EnabledState.DISABLED); + if (actions.modifyAnnouncementsOnly != null) { + builder.newIsAnnouncementGroup(actions.modifyAnnouncementsOnly.announcementsOnly ? EnabledState.ENABLED : EnabledState.DISABLED); } // Field 22 - for (GroupChange.Actions.AddBannedMemberAction action : actions.getAddBannedMembersList()) { - builder.addNewBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBytes(decryptServiceIdToBinary(action.getAdded().getUserId())).setTimestamp(action.getAdded().getTimestamp()).build()); + List newBannedMembers = new ArrayList<>(actions.addBannedMembers.size()); + for (GroupChange.Actions.AddBannedMemberAction action : actions.addBannedMembers) { + newBannedMembers.add(new DecryptedBannedMember.Builder().serviceIdBytes(decryptServiceIdToBinary(action.added.userId)).timestamp(action.added.timestamp).build()); } + builder.newBannedMembers(newBannedMembers); // Field 23 - for (GroupChange.Actions.DeleteBannedMemberAction action : actions.getDeleteBannedMembersList()) { - builder.addDeleteBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBytes(decryptServiceIdToBinary(action.getDeletedUserId())).build()); + List deleteBannedMembers = new ArrayList<>(actions.deleteBannedMembers.size()); + for (GroupChange.Actions.DeleteBannedMemberAction action : actions.deleteBannedMembers) { + deleteBannedMembers.add(new DecryptedBannedMember.Builder().serviceIdBytes(decryptServiceIdToBinary(action.deletedUserId)).build()); } + builder.deleteBannedMembers(deleteBannedMembers); // Field 24 - for (GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction promotePendingPniAciMemberAction : actions.getPromotePendingPniAciMembersList()) { - ACI aci = decryptAci(promotePendingPniAciMemberAction.getUserId()); - ServiceId pni = decryptServiceId(promotePendingPniAciMemberAction.getPni()); - ProfileKey profileKey = decryptProfileKey(promotePendingPniAciMemberAction.getProfileKey(), aci); + List promotePendingPniAciMembers = new ArrayList<>(actions.promotePendingPniAciMembers.size()); + for (GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction promotePendingPniAciMemberAction : actions.promotePendingPniAciMembers) { + ACI aci = decryptAci(promotePendingPniAciMemberAction.userId); + ServiceId pni = decryptServiceId(promotePendingPniAciMemberAction.pni); + ProfileKey profileKey = decryptProfileKey(promotePendingPniAciMemberAction.profileKey, aci); if (!(pni instanceof PNI)) { throw new InvalidGroupStateException(); } - builder.setEditorServiceIdBytes(aci.toByteString()) - .addPromotePendingPniAciMembers(DecryptedMember.newBuilder() - .setAciBytes(aci.toByteString()) - .setRole(Member.Role.DEFAULT) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setJoinedAtRevision(actions.getRevision()) - .setPniBytes(pni.toByteString())); + builder.editorServiceIdBytes(aci.toByteString()); + promotePendingPniAciMembers.add(new DecryptedMember.Builder() + .aciBytes(aci.toByteString()) + .role(Member.Role.DEFAULT) + .profileKey(ByteString.of(profileKey.serialize())) + .joinedAtRevision(actions.revision) + .pniBytes(pni.toByteString()) + .build()); } + builder.promotePendingPniAciMembers(promotePendingPniAciMembers); return builder.build(); } public DecryptedGroupJoinInfo decryptGroupJoinInfo(GroupJoinInfo joinInfo) { - return DecryptedGroupJoinInfo.newBuilder() - .setTitle(decryptTitle(joinInfo.getTitle())) - .setAvatar(joinInfo.getAvatar()) - .setMemberCount(joinInfo.getMemberCount()) - .setAddFromInviteLink(joinInfo.getAddFromInviteLink()) - .setRevision(joinInfo.getRevision()) - .setPendingAdminApproval(joinInfo.getPendingAdminApproval()) - .setDescription(decryptDescription(joinInfo.getDescription())) - .build(); + return new DecryptedGroupJoinInfo.Builder() + .title(decryptTitle(joinInfo.title)) + .avatar(joinInfo.avatar) + .memberCount(joinInfo.memberCount) + .addFromInviteLink(joinInfo.addFromInviteLink) + .revision(joinInfo.revision) + .pendingAdminApproval(joinInfo.pendingAdminApproval) + .description(decryptDescription(joinInfo.description)) + .build(); } private DecryptedMember.Builder decryptMember(Member member) throws InvalidGroupStateException, VerificationFailedException, InvalidInputException { - if (member.getPresentation().isEmpty()) { - ACI aci = decryptAci(member.getUserId()); + if (member.presentation.size() == 0) { + ACI aci = decryptAci(member.userId); - return DecryptedMember.newBuilder() - .setAciBytes(aci.toByteString()) - .setJoinedAtRevision(member.getJoinedAtRevision()) - .setProfileKey(decryptProfileKeyToByteString(member.getProfileKey(), aci)) - .setRole(member.getRole()); + return new DecryptedMember.Builder() + .aciBytes(aci.toByteString()) + .joinedAtRevision(member.joinedAtRevision) + .profileKey(decryptProfileKeyToByteString(member.profileKey, aci)) + .role(member.role); } else { - ProfileKeyCredentialPresentation profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(member.getPresentation().toByteArray()); + ProfileKeyCredentialPresentation profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(member.presentation.toByteArray()); ServiceId serviceId = ServiceId.fromLibSignal(clientZkGroupCipher.decrypt(profileKeyCredentialPresentation.getUuidCiphertext())); if (!(serviceId instanceof ACI)) { throw new InvalidGroupStateException(); } - ACI aci = (ACI) serviceId; + ACI aci = (ACI) serviceId; ProfileKey profileKey = clientZkGroupCipher.decryptProfileKey(profileKeyCredentialPresentation.getProfileKeyCiphertext(), aci.getLibSignalAci()); - return DecryptedMember.newBuilder() - .setAciBytes(aci.toByteString()) - .setJoinedAtRevision(member.getJoinedAtRevision()) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setRole(member.getRole()); + return new DecryptedMember.Builder() + .aciBytes(aci.toByteString()) + .joinedAtRevision(member.joinedAtRevision) + .profileKey(ByteString.of(profileKey.serialize())) + .role(member.role); } } private DecryptedPendingMember decryptMember(PendingMember member) throws InvalidGroupStateException, VerificationFailedException { - ByteString userIdCipherText = member.getMember().getUserId(); + ByteString userIdCipherText = member.member.userId; ServiceId serviceId = decryptServiceIdOrUnknown(userIdCipherText); - ACI addedBy = decryptAci(member.getAddedByUserId()); + ACI addedBy = decryptAci(member.addedByUserId); - Member.Role role = member.getMember().getRole(); + Member.Role role = member.member.role; if (role != Member.Role.ADMINISTRATOR && role != Member.Role.DEFAULT) { role = Member.Role.DEFAULT; } - return DecryptedPendingMember.newBuilder() - .setServiceIdBytes(serviceId.toByteString()) - .setServiceIdCipherText(userIdCipherText) - .setAddedByAci(addedBy.toByteString()) - .setRole(role) - .setTimestamp(member.getTimestamp()) - .build(); + return new DecryptedPendingMember.Builder() + .serviceIdBytes(serviceId.toByteString()) + .serviceIdCipherText(userIdCipherText) + .addedByAci(addedBy.toByteString()) + .role(role) + .timestamp(member.timestamp) + .build(); } private DecryptedRequestingMember decryptRequestingMember(RequestingMember member) throws InvalidGroupStateException, VerificationFailedException { - if (member.getPresentation().isEmpty()) { - ACI aci = decryptAci(member.getUserId()); + if (member.presentation.size() == 0) { + ACI aci = decryptAci(member.userId); - return DecryptedRequestingMember.newBuilder() - .setAciBytes(aci.toByteString()) - .setProfileKey(decryptProfileKeyToByteString(member.getProfileKey(), aci)) - .setTimestamp(member.getTimestamp()) - .build(); + return new DecryptedRequestingMember.Builder() + .aciBytes(aci.toByteString()) + .profileKey(decryptProfileKeyToByteString(member.profileKey, aci)) + .timestamp(member.timestamp) + .build(); } else { ProfileKeyCredentialPresentation profileKeyCredentialPresentation; try { - profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(member.getPresentation().toByteArray()); + profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(member.presentation.toByteArray()); } catch (InvalidInputException e) { throw new InvalidGroupStateException(e); } @@ -850,10 +854,10 @@ public final class GroupsV2Operations { ProfileKey profileKey = clientZkGroupCipher.decryptProfileKey(profileKeyCredentialPresentation.getProfileKeyCiphertext(), aci.getLibSignalAci()); - return DecryptedRequestingMember.newBuilder() - .setAciBytes(aci.toByteString()) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .build(); + return new DecryptedRequestingMember.Builder() + .aciBytes(aci.toByteString()) + .profileKey(ByteString.of(profileKey.serialize())) + .build(); } } @@ -867,7 +871,7 @@ public final class GroupsV2Operations { } private ByteString decryptProfileKeyToByteString(ByteString profileKey, ACI aci) throws VerificationFailedException, InvalidGroupStateException { - return ByteString.copyFrom(decryptProfileKey(profileKey, aci).serialize()); + return ByteString.of(decryptProfileKey(profileKey, aci).serialize()); } private ByteString decryptServiceIdToBinary(ByteString userId) throws InvalidGroupStateException, VerificationFailedException { @@ -880,7 +884,7 @@ public final class GroupsV2Operations { // Visible for Testing public ByteString encryptServiceId(ServiceId serviceId) { - return ByteString.copyFrom(clientZkGroupCipher.encrypt(serviceId.getLibSignalServiceId()).serialize()); + return ByteString.of(clientZkGroupCipher.encrypt(serviceId.getLibSignalServiceId()).serialize()); } private ServiceId decryptServiceId(ByteString userId) throws InvalidGroupStateException, VerificationFailedException { @@ -925,38 +929,41 @@ public final class GroupsV2Operations { ByteString encryptTitle(String title) { try { - GroupAttributeBlob blob = GroupAttributeBlob.newBuilder().setTitle(title).build(); + GroupAttributeBlob blob = new GroupAttributeBlob.Builder().title(title).build(); - return ByteString.copyFrom(clientZkGroupCipher.encryptBlob(blob.toByteArray())); + return ByteString.of(clientZkGroupCipher.encryptBlob(blob.encode())); } catch (VerificationFailedException e) { throw new AssertionError(e); } } private String decryptTitle(ByteString cipherText) { - return decryptBlob(cipherText).getTitle().trim(); + String title = decryptBlob(cipherText).title; + return title != null ? title.trim() : ""; } ByteString encryptDescription(String description) { try { - GroupAttributeBlob blob = GroupAttributeBlob.newBuilder().setDescription(description).build(); + GroupAttributeBlob blob = new GroupAttributeBlob.Builder().description(description).build(); - return ByteString.copyFrom(clientZkGroupCipher.encryptBlob(blob.toByteArray())); + return ByteString.of(clientZkGroupCipher.encryptBlob(blob.encode())); } catch (VerificationFailedException e) { throw new AssertionError(e); } } private String decryptDescription(ByteString cipherText) { - return decryptBlob(cipherText).getDescription().trim(); + String description = decryptBlob(cipherText).description; + return description != null ? description.trim() : ""; } private int decryptDisappearingMessagesTimer(ByteString encryptedTimerMessage) { - return decryptBlob(encryptedTimerMessage).getDisappearingMessagesDuration(); + Integer disappearingMessagesDuration = decryptBlob(encryptedTimerMessage).disappearingMessagesDuration; + return disappearingMessagesDuration != null ? disappearingMessagesDuration : 0; } public byte[] decryptAvatar(byte[] bytes) { - return decryptBlob(bytes).getAvatar().toByteArray(); + return decryptBlob(bytes).avatar.toByteArray(); } private GroupAttributeBlob decryptBlob(ByteString blob) { @@ -966,26 +973,26 @@ public final class GroupsV2Operations { private GroupAttributeBlob decryptBlob(byte[] bytes) { // TODO GV2: Minimum field length checking should be responsibility of clientZkGroupCipher#decryptBlob if (bytes == null || bytes.length == 0) { - return GroupAttributeBlob.getDefaultInstance(); + return new GroupAttributeBlob(); } if (bytes.length < 29) { Log.w(TAG, "Bad encrypted blob length"); - return GroupAttributeBlob.getDefaultInstance(); + return new GroupAttributeBlob(); } try { - return GroupAttributeBlob.parseFrom(clientZkGroupCipher.decryptBlob(bytes)); - } catch (InvalidProtocolBufferException | VerificationFailedException e) { + return GroupAttributeBlob.ADAPTER.decode(clientZkGroupCipher.decryptBlob(bytes)); + } catch (IOException | VerificationFailedException e) { Log.w(TAG, "Bad encrypted blob"); - return GroupAttributeBlob.getDefaultInstance(); + return new GroupAttributeBlob(); } } ByteString encryptTimer(int timerDurationSeconds) { try { - GroupAttributeBlob timer = GroupAttributeBlob.newBuilder() - .setDisappearingMessagesDuration(timerDurationSeconds) - .build(); - return ByteString.copyFrom(clientZkGroupCipher.encryptBlob(timer.toByteArray())); + GroupAttributeBlob timer = new GroupAttributeBlob.Builder() + .disappearingMessagesDuration(timerDurationSeconds) + .build(); + return ByteString.of(clientZkGroupCipher.encryptBlob(timer.encode())); } catch (VerificationFailedException e) { throw new AssertionError(e); } @@ -995,13 +1002,13 @@ public final class GroupsV2Operations { * Verifies signature and parses actions on a group change. */ private GroupChange.Actions getVerifiedActions(GroupChange groupChange) - throws VerificationFailedException, InvalidProtocolBufferException + throws VerificationFailedException, IOException { - byte[] actionsByteArray = groupChange.getActions().toByteArray(); + byte[] actionsByteArray = groupChange.actions.toByteArray(); NotarySignature signature; try { - signature = new NotarySignature(groupChange.getServerSignature().toByteArray()); + signature = new NotarySignature(groupChange.serverSignature.toByteArray()); } catch (InvalidInputException e) { Log.w(TAG, "Invalid input while verifying group change", e); throw new VerificationFailedException(); @@ -1009,30 +1016,29 @@ public final class GroupsV2Operations { serverPublicParams.verifySignature(actionsByteArray, signature); - return GroupChange.Actions.parseFrom(actionsByteArray); + return GroupChange.Actions.ADAPTER.decode(actionsByteArray); } /** * Parses actions on a group change without verification. */ private GroupChange.Actions getActions(GroupChange groupChange) - throws InvalidProtocolBufferException + throws IOException { - return GroupChange.Actions.parseFrom(groupChange.getActions()); + return GroupChange.Actions.ADAPTER.decode(groupChange.actions); } public GroupChange.Actions.Builder createChangeMemberRole(ACI memberAci, Member.Role role) { - return GroupChange.Actions.newBuilder() - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder() - .setUserId(encryptServiceId(memberAci)) - .setRole(role)); + return new GroupChange.Actions.Builder().modifyMemberRoles(Collections.singletonList( + new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encryptServiceId(memberAci)).role(role).build() + )); } public List decryptAddMembers(List addMembers) throws InvalidInputException, VerificationFailedException { List ids = new ArrayList<>(addMembers.size()); for (int i = 0; i < addMembers.size(); i++) { GroupChange.Actions.AddMemberAction addMember = addMembers.get(i); - ProfileKeyCredentialPresentation profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(addMember.getAdded().getPresentation().toByteArray()); + ProfileKeyCredentialPresentation profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(addMember.added.presentation.toByteArray()); ids.add(ServiceId.fromLibSignal(clientZkGroupCipher.decrypt(profileKeyCredentialPresentation.getUuidCiphertext()))); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/PartialDecryptedGroup.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/PartialDecryptedGroup.java index 1b8dcea2f3..c603e356dc 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/PartialDecryptedGroup.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/PartialDecryptedGroup.java @@ -34,15 +34,15 @@ public class PartialDecryptedGroup { } public int getRevision() { - return decryptedGroup.getRevision(); + return decryptedGroup.revision; } public List getMembersList() { - return decryptedGroup.getMembersList(); + return decryptedGroup.members; } public List getPendingMembersList() { - return decryptedGroup.getPendingMembersList(); + return decryptedGroup.pendingMembers; } public DecryptedGroup getFullyDecryptedGroup() diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt index 3726940336..42efc68dcd 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt @@ -7,16 +7,16 @@ import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialPresentation import org.whispersystems.signalservice.api.InvalidMessageStructureException 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.SignalServiceProtos.AttachmentPointer -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2 -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.ReceiptMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.StoryMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.TypingMessage +import org.whispersystems.signalservice.internal.push.AttachmentPointer +import org.whispersystems.signalservice.internal.push.Content +import org.whispersystems.signalservice.internal.push.DataMessage +import org.whispersystems.signalservice.internal.push.EditMessage +import org.whispersystems.signalservice.internal.push.Envelope +import org.whispersystems.signalservice.internal.push.GroupContextV2 +import org.whispersystems.signalservice.internal.push.ReceiptMessage +import org.whispersystems.signalservice.internal.push.StoryMessage +import org.whispersystems.signalservice.internal.push.SyncMessage +import org.whispersystems.signalservice.internal.push.TypingMessage /** * Validates an [Envelope] and its decrypted [Content] so that we know the message can be processed safely @@ -35,38 +35,38 @@ object EnvelopeContentValidator { } } - if (envelope.hasSourceServiceId() && envelope.sourceServiceId.isInvalidServiceId()) { + if (envelope.sourceServiceId != null && envelope.sourceServiceId.isInvalidServiceId()) { return Result.Invalid("Envelope had an invalid sourceServiceId!") } // Reminder: envelope.destinationServiceId was already validated since we need that for decryption return when { - envelope.story && !content.meetsStoryFlagCriteria() -> Result.Invalid("Envelope was flagged as a story, but it did not have any story-related content!") - content.hasDataMessage() -> validateDataMessage(envelope, content.dataMessage) - content.hasSyncMessage() -> validateSyncMessage(envelope, content.syncMessage) - content.hasCallMessage() -> Result.Valid - content.hasNullMessage() -> Result.Valid - content.hasReceiptMessage() -> validateReceiptMessage(content.receiptMessage) - content.hasTypingMessage() -> validateTypingMessage(envelope, content.typingMessage) - content.hasDecryptionErrorMessage() -> validateDecryptionErrorMessage(content.decryptionErrorMessage.toByteArray()) - content.hasStoryMessage() -> validateStoryMessage(content.storyMessage) - content.hasPniSignatureMessage() -> Result.Valid - content.hasSenderKeyDistributionMessage() -> Result.Valid - content.hasEditMessage() -> validateEditMessage(content.editMessage) + envelope.story == true && !content.meetsStoryFlagCriteria() -> Result.Invalid("Envelope was flagged as a story, but it did not have any story-related content!") + content.dataMessage != null -> validateDataMessage(envelope, content.dataMessage) + content.syncMessage != null -> validateSyncMessage(envelope, content.syncMessage) + content.callMessage != null -> Result.Valid + content.nullMessage != null -> Result.Valid + content.receiptMessage != null -> validateReceiptMessage(content.receiptMessage) + content.typingMessage != null -> validateTypingMessage(envelope, content.typingMessage) + content.decryptionErrorMessage != null -> validateDecryptionErrorMessage(content.decryptionErrorMessage.toByteArray()) + content.storyMessage != null -> validateStoryMessage(content.storyMessage) + content.pniSignatureMessage != null -> Result.Valid + content.senderKeyDistributionMessage != null -> Result.Valid + content.editMessage != null -> validateEditMessage(content.editMessage) else -> Result.Invalid("Content is empty!") } } private fun validateDataMessage(envelope: Envelope, dataMessage: DataMessage): Result { - if (dataMessage.requiredProtocolVersion > DataMessage.ProtocolVersion.CURRENT_VALUE) { + if (dataMessage.requiredProtocolVersion != null && dataMessage.requiredProtocolVersion > DataMessage.ProtocolVersion.CURRENT.value) { return Result.UnsupportedDataMessage( - ourVersion = DataMessage.ProtocolVersion.CURRENT_VALUE, + ourVersion = DataMessage.ProtocolVersion.CURRENT.value, theirVersion = dataMessage.requiredProtocolVersion ) } - if (!dataMessage.hasTimestamp()) { + if (dataMessage.timestamp == null) { return Result.Invalid("[DataMessage] Missing timestamp!") } @@ -74,65 +74,61 @@ object EnvelopeContentValidator { Result.Invalid("[DataMessage] Timestamps don't match! envelope: ${envelope.timestamp}, content: ${dataMessage.timestamp}") } - if (dataMessage.hasQuote() && dataMessage.quote.authorAci.isNullOrInvalidAci()) { + if (dataMessage.quote != null && dataMessage.quote.authorAci.isNullOrInvalidAci()) { return Result.Invalid("[DataMessage] Invalid ACI on quote!") } - if (dataMessage.contactList.any { it.hasAvatar() && it.avatar.avatar.isPresentAndInvalid() }) { + if (dataMessage.contact.any { it.avatar != null && it.avatar.avatar.isPresentAndInvalid() }) { return Result.Invalid("[DataMessage] Invalid AttachmentPointer on DataMessage.contactList.avatar!") } - if (dataMessage.contactList.any { it.hasAvatar() && it.avatar.avatar.isPresentAndInvalid() }) { - return Result.Invalid("[DataMessage] Invalid AttachmentPointer on DataMessage.contactList.avatar!") - } - - if (dataMessage.previewList.any { it.hasImage() && it.image.isPresentAndInvalid() }) { + if (dataMessage.preview.any { it.image != null && it.image.isPresentAndInvalid() }) { return Result.Invalid("[DataMessage] Invalid AttachmentPointer on DataMessage.previewList.image!") } - if (dataMessage.bodyRangesList.any { it.hasMentionAci() && it.mentionAci.isNullOrInvalidAci() }) { + if (dataMessage.bodyRanges.any { it.mentionAci != null && it.mentionAci.isNullOrInvalidAci() }) { return Result.Invalid("[DataMessage] Invalid ACI on body range!") } - if (dataMessage.hasSticker() && dataMessage.sticker.data.isNullOrInvalid()) { + if (dataMessage.sticker != null && dataMessage.sticker.data_.isNullOrInvalid()) { return Result.Invalid("[DataMessage] Invalid AttachmentPointer on DataMessage.sticker!") } - if (dataMessage.hasReaction()) { - if (!dataMessage.reaction.hasTargetSentTimestamp()) { + if (dataMessage.reaction != null) { + if (dataMessage.reaction.targetSentTimestamp == null) { return Result.Invalid("[DataMessage] Missing timestamp on DataMessage.reaction!") } + if (dataMessage.reaction.targetAuthorAci.isNullOrInvalidAci()) { return Result.Invalid("[DataMessage] Invalid ACI on DataMessage.reaction!") } } - if (dataMessage.hasDelete() && !dataMessage.delete.hasTargetSentTimestamp()) { + if (dataMessage.delete != null && dataMessage.delete.targetSentTimestamp == null) { return Result.Invalid("[DataMessage] Missing timestamp on DataMessage.delete!") } - if (dataMessage.hasStoryContext() && dataMessage.storyContext.authorAci.isNullOrInvalidAci()) { + if (dataMessage.storyContext != null && dataMessage.storyContext.authorAci.isNullOrInvalidAci()) { return Result.Invalid("[DataMessage] Invalid ACI on DataMessage.storyContext!") } - if (dataMessage.hasGiftBadge()) { - if (!dataMessage.giftBadge.hasReceiptCredentialPresentation()) { + if (dataMessage.giftBadge != null) { + if (dataMessage.giftBadge.receiptCredentialPresentation == null) { return Result.Invalid("[DataMessage] Missing DataMessage.giftBadge.receiptCredentialPresentation!") } - if (!dataMessage.giftBadge.hasReceiptCredentialPresentation()) { - try { - ReceiptCredentialPresentation(dataMessage.giftBadge.receiptCredentialPresentation.toByteArray()) - } catch (e: InvalidInputException) { - return Result.Invalid("[DataMessage] Invalid DataMessage.giftBadge.receiptCredentialPresentation!") - } + + try { + ReceiptCredentialPresentation(dataMessage.giftBadge.receiptCredentialPresentation.toByteArray()) + } catch (e: InvalidInputException) { + return Result.Invalid("[DataMessage] Invalid DataMessage.giftBadge.receiptCredentialPresentation!") } } - if (dataMessage.attachmentsList.any { it.isNullOrInvalid() }) { + if (dataMessage.attachments.any { it.isNullOrInvalid() }) { return Result.Invalid("[DataMessage] Invalid attachments!") } - if (dataMessage.hasGroupV2()) { + if (dataMessage.groupV2 != null) { validateGroupContextV2(dataMessage.groupV2, "[DataMessage]")?.let { return it } } @@ -140,77 +136,77 @@ object EnvelopeContentValidator { } private fun validateSyncMessage(envelope: Envelope, syncMessage: SyncMessage): Result { - if (syncMessage.hasSent()) { + if (syncMessage.sent != null) { val validAddress = syncMessage.sent.destinationServiceId.isValidServiceId() - val hasDataGroup = syncMessage.sent.message?.hasGroupV2() ?: false - val hasStoryGroup = syncMessage.sent.storyMessage?.hasGroup() ?: false - val hasStoryManifest = syncMessage.sent.storyMessageRecipientsList.isNotEmpty() - val hasEditMessageGroup = syncMessage.sent.editMessage?.dataMessage?.hasGroupV2() ?: false + val hasDataGroup = syncMessage.sent.message?.groupV2 != null + val hasStoryGroup = syncMessage.sent.storyMessage?.group != null + val hasStoryManifest = syncMessage.sent.storyMessageRecipients.isNotEmpty() + val hasEditMessageGroup = syncMessage.sent.editMessage?.dataMessage?.groupV2 != null if (hasDataGroup) { - validateGroupContextV2(syncMessage.sent.message.groupV2, "[SyncMessage.Sent.Message]")?.let { return it } + validateGroupContextV2(syncMessage.sent.message!!.groupV2!!, "[SyncMessage.Sent.Message]")?.let { return it } } if (hasStoryGroup) { - validateGroupContextV2(syncMessage.sent.storyMessage.group, "[SyncMessage.Sent.StoryMessage]")?.let { return it } + validateGroupContextV2(syncMessage.sent.storyMessage!!.group!!, "[SyncMessage.Sent.StoryMessage]")?.let { return it } } if (hasEditMessageGroup) { - validateGroupContextV2(syncMessage.sent.editMessage.dataMessage.groupV2, "[SyncMessage.Sent.EditMessage]")?.let { return it } + validateGroupContextV2(syncMessage.sent.editMessage!!.dataMessage!!.groupV2!!, "[SyncMessage.Sent.EditMessage]")?.let { return it } } if (!validAddress && !hasDataGroup && !hasStoryGroup && !hasStoryManifest && !hasEditMessageGroup) { return Result.Invalid("[SyncMessage] No valid destination! Checked the destination, DataMessage.group, StoryMessage.group, EditMessage.group and storyMessageRecipientList") } - for (status in syncMessage.sent.unidentifiedStatusList) { + for (status in syncMessage.sent.unidentifiedStatus) { if (status.destinationServiceId.isNullOrInvalidServiceId()) { return Result.Invalid("[SyncMessage] Invalid ServiceId in SyncMessage.sent.unidentifiedStatusList!") } } - return if (syncMessage.sent.hasMessage()) { + return if (syncMessage.sent.message != null) { validateDataMessage(envelope, syncMessage.sent.message) - } else if (syncMessage.sent.hasStoryMessage()) { + } else if (syncMessage.sent.storyMessage != null) { validateStoryMessage(syncMessage.sent.storyMessage) - } else if (syncMessage.sent.storyMessageRecipientsList.isNotEmpty()) { + } else if (syncMessage.sent.storyMessageRecipients.isNotEmpty()) { Result.Valid - } else if (syncMessage.sent.hasEditMessage()) { + } else if (syncMessage.sent.editMessage != null) { validateEditMessage(syncMessage.sent.editMessage) } else { Result.Invalid("[SyncMessage] Empty SyncMessage.sent!") } } - if (syncMessage.readList.any { it.senderAci.isNullOrInvalidAci() }) { + if (syncMessage.read.any { it.senderAci.isNullOrInvalidAci() }) { return Result.Invalid("[SyncMessage] Invalid ACI in SyncMessage.readList!") } - if (syncMessage.viewedList.any { it.senderAci.isNullOrInvalidAci() }) { + if (syncMessage.viewed.any { it.senderAci.isNullOrInvalidAci() }) { return Result.Invalid("[SyncMessage] Invalid ACI in SyncMessage.viewList!") } - if (syncMessage.hasViewOnceOpen() && syncMessage.viewOnceOpen.senderAci.isNullOrInvalidAci()) { + if (syncMessage.viewOnceOpen != null && syncMessage.viewOnceOpen.senderAci.isNullOrInvalidAci()) { return Result.Invalid("[SyncMessage] Invalid ACI in SyncMessage.viewOnceOpen!") } - if (syncMessage.hasVerified() && syncMessage.verified.destinationAci.isNullOrInvalidAci()) { + if (syncMessage.verified != null && syncMessage.verified.destinationAci.isNullOrInvalidAci()) { return Result.Invalid("[SyncMessage] Invalid ACI in SyncMessage.verified!") } - if (syncMessage.stickerPackOperationList.any { !it.hasPackId() }) { + if (syncMessage.stickerPackOperation.any { it.packId == null }) { return Result.Invalid("[SyncMessage] Missing packId in stickerPackOperationList!") } - if (syncMessage.hasBlocked() && syncMessage.blocked.acisList.any { it.isNullOrInvalidAci() }) { + if (syncMessage.blocked != null && syncMessage.blocked.acis.any { it.isNullOrInvalidAci() }) { return Result.Invalid("[SyncMessage] Invalid ACI in SyncMessage.blocked!") } - if (syncMessage.hasMessageRequestResponse() && !syncMessage.messageRequestResponse.hasGroupId() && syncMessage.messageRequestResponse.threadAci.isNullOrInvalidAci()) { + if (syncMessage.messageRequestResponse != null && syncMessage.messageRequestResponse.groupId == null && syncMessage.messageRequestResponse.threadAci.isNullOrInvalidAci()) { return Result.Invalid("[SyncMessage] Invalid ACI in SyncMessage.messageRequestResponse!") } - if (syncMessage.hasOutgoingPayment() && syncMessage.outgoingPayment.recipientServiceId.isNullOrInvalidServiceId()) { + if (syncMessage.outgoingPayment != null && syncMessage.outgoingPayment.recipientServiceId.isNullOrInvalidServiceId()) { return Result.Invalid("[SyncMessage] Invalid ServiceId in SyncMessage.outgoingPayment!") } @@ -218,7 +214,7 @@ object EnvelopeContentValidator { } private fun validateReceiptMessage(receiptMessage: ReceiptMessage): Result { - return if (!receiptMessage.hasType()) { + return if (receiptMessage.type == null) { Result.Invalid("[ReceiptMessage] Missing type!") } else { Result.Valid @@ -226,11 +222,11 @@ object EnvelopeContentValidator { } private fun validateTypingMessage(envelope: Envelope, typingMessage: TypingMessage): Result { - return if (!typingMessage.hasTimestamp()) { + return if (typingMessage.timestamp == null) { return Result.Invalid("[TypingMessage] Missing timestamp!") - } else if (typingMessage.hasTimestamp() && typingMessage.timestamp != envelope.timestamp) { + } else if (typingMessage.timestamp != envelope.timestamp) { Result.Invalid("[TypingMessage] Timestamps don't match! envelope: ${envelope.timestamp}, content: ${typingMessage.timestamp}") - } else if (!typingMessage.hasAction()) { + } else if (typingMessage.action == null) { Result.Invalid("[TypingMessage] Missing action!") } else { Result.Valid @@ -247,44 +243,44 @@ object EnvelopeContentValidator { } private fun validateStoryMessage(storyMessage: StoryMessage): Result { - if (storyMessage.hasGroup()) { + if (storyMessage.group != null) { validateGroupContextV2(storyMessage.group, "[StoryMessage]")?.let { return it } } return Result.Valid } - private fun validateEditMessage(editMessage: SignalServiceProtos.EditMessage): Result { - if (!editMessage.hasDataMessage()) { + private fun validateEditMessage(editMessage: EditMessage): Result { + if (editMessage.dataMessage == null) { return Result.Invalid("[EditMessage] No data message present") } - if (!editMessage.hasTargetSentTimestamp()) { + if (editMessage.targetSentTimestamp == null) { return Result.Invalid("[EditMessage] No targetSentTimestamp specified") } val dataMessage: DataMessage = editMessage.dataMessage - if (dataMessage.requiredProtocolVersion > DataMessage.ProtocolVersion.CURRENT_VALUE) { + if (dataMessage.requiredProtocolVersion != null && dataMessage.requiredProtocolVersion > DataMessage.ProtocolVersion.CURRENT.value) { return Result.UnsupportedDataMessage( - ourVersion = DataMessage.ProtocolVersion.CURRENT_VALUE, + ourVersion = DataMessage.ProtocolVersion.CURRENT.value, theirVersion = dataMessage.requiredProtocolVersion ) } - if (dataMessage.previewList.any { it.hasImage() && it.image.isPresentAndInvalid() }) { + if (dataMessage.preview.any { it.image != null && it.image.isPresentAndInvalid() }) { return Result.Invalid("[EditMessage] Invalid AttachmentPointer on DataMessage.previewList.image!") } - if (dataMessage.bodyRangesList.any { it.hasMentionAci() && it.mentionAci.isNullOrInvalidAci() }) { + if (dataMessage.bodyRanges.any { it.mentionAci != null && it.mentionAci.isNullOrInvalidAci() }) { return Result.Invalid("[EditMessage] Invalid UUID on body range!") } - if (dataMessage.attachmentsList.any { it.isNullOrInvalid() }) { + if (dataMessage.attachments.any { it.isNullOrInvalid() }) { return Result.Invalid("[EditMessage] Invalid attachments!") } - if (dataMessage.hasGroupV2()) { + if (dataMessage.groupV2 != null) { validateGroupContextV2(dataMessage.groupV2, "[EditMessage]")?.let { return it } } @@ -292,11 +288,11 @@ object EnvelopeContentValidator { } private fun AttachmentPointer?.isNullOrInvalid(): Boolean { - return this == null || this.attachmentIdentifierCase == AttachmentPointer.AttachmentIdentifierCase.ATTACHMENTIDENTIFIER_NOT_SET + return this == null || (this.cdnId == null && this.cdnKey == null) } private fun AttachmentPointer?.isPresentAndInvalid(): Boolean { - return this != null && this.attachmentIdentifierCase == AttachmentPointer.AttachmentIdentifierCase.ATTACHMENTIDENTIFIER_NOT_SET + return this != null && (this.cdnId == null && this.cdnKey == null) } private fun String?.isValidServiceId(): Boolean { @@ -322,10 +318,10 @@ object EnvelopeContentValidator { private fun Content?.meetsStoryFlagCriteria(): Boolean { return when { this == null -> false - this.hasSenderKeyDistributionMessage() -> true - this.hasStoryMessage() -> true - this.hasDataMessage() && this.dataMessage.hasStoryContext() && this.dataMessage.hasGroupV2() -> true - this.hasDataMessage() && this.dataMessage.hasDelete() -> true + this.senderKeyDistributionMessage != null -> true + this.storyMessage != null -> true + this.dataMessage != null && this.dataMessage.storyContext != null && this.dataMessage.groupV2 != null -> true + this.dataMessage != null && this.dataMessage.delete != null -> true else -> false } } @@ -333,34 +329,34 @@ object EnvelopeContentValidator { private fun createPlaintextResultIfInvalid(content: Content): Result? { val errors: MutableList = mutableListOf() - if (!content.hasDecryptionErrorMessage()) { + if (content.decryptionErrorMessage == null) { errors += "Missing DecryptionErrorMessage" } - if (content.hasStoryMessage()) { + if (content.storyMessage != null) { errors += "Unexpected StoryMessage" } - if (content.hasSenderKeyDistributionMessage()) { + if (content.senderKeyDistributionMessage != null) { errors += "Unexpected SenderKeyDistributionMessage" } - if (content.hasCallMessage()) { + if (content.callMessage != null) { errors += "Unexpected CallMessage" } - if (content.hasEditMessage()) { + if (content.editMessage != null) { errors += "Unexpected EditMessage" } - if (content.hasNullMessage()) { + if (content.nullMessage != null) { errors += "Unexpected NullMessage" } - if (content.hasPniSignatureMessage()) { + if (content.pniSignatureMessage != null) { errors += "Unexpected PniSignatureMessage" } - if (content.hasReceiptMessage()) { + if (content.receiptMessage != null) { errors += "Unexpected ReceiptMessage" } - if (content.hasSyncMessage()) { + if (content.syncMessage != null) { errors += "Unexpected SyncMessage" } - if (content.hasTypingMessage()) { + if (content.typingMessage != null) { errors += "Unexpected TypingMessage" } @@ -372,9 +368,9 @@ object EnvelopeContentValidator { } private fun validateGroupContextV2(groupContext: GroupContextV2, prefix: String): Result.Invalid? { - return if (!groupContext.hasMasterKey()) { + return if (groupContext.masterKey == null) { Result.Invalid("$prefix Missing GV2 master key!") - } else if (!groupContext.hasRevision()) { + } else if (groupContext.revision == null) { Result.Invalid("$prefix Missing GV2 revision!") } else { try { @@ -390,8 +386,8 @@ object EnvelopeContentValidator { /** Content is valid. */ object Valid : Result() - /** The [DataMessage.requiredProtocolVersion_] is newer than the one we support. */ - class UnsupportedDataMessage(val ourVersion: Int, val theirVersion: Int) : Result() + /** The [DataMessage.requiredProtocolVersion] is newer than the one we support. */ + class UnsupportedDataMessage(val ourVersion: Int, val theirVersion: Int?) : Result() /** The contents of the proto do not match our expectations, e.g. invalid UUIDs, missing required fields, etc. */ class Invalid(val reason: String, val throwable: Throwable = Throwable()) : Result() diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeResponse.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeResponse.kt index b44848a928..801f1743ce 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeResponse.kt +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeResponse.kt @@ -1,6 +1,6 @@ package org.whispersystems.signalservice.api.messages -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope +import org.whispersystems.signalservice.internal.push.Envelope import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage /** diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SendMessageResult.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SendMessageResult.java index a837b06bfe..144207e439 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SendMessageResult.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SendMessageResult.java @@ -5,7 +5,7 @@ import org.signal.libsignal.protocol.IdentityKey; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; import org.whispersystems.signalservice.api.push.exceptions.RateLimitException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content; +import org.whispersystems.signalservice.internal.push.Content; import java.util.List; import java.util.Optional; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceAttachmentRemoteId.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceAttachmentRemoteId.java index bb5452d728..5b5af120f7 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceAttachmentRemoteId.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceAttachmentRemoteId.java @@ -1,7 +1,7 @@ package org.whispersystems.signalservice.api.messages; import org.whispersystems.signalservice.api.InvalidMessageStructureException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer; +import org.whispersystems.signalservice.internal.push.AttachmentPointer; import java.util.Optional; @@ -13,57 +13,55 @@ import java.util.Optional; * flexibility in the amount of entropy present. */ public final class SignalServiceAttachmentRemoteId { - private final Optional v2; - private final Optional v3; + private final Optional v2; + private final Optional v3; - public SignalServiceAttachmentRemoteId(long v2) { - this.v2 = Optional.of(v2); - this.v3 = Optional.empty(); - } + public SignalServiceAttachmentRemoteId(long v2) { + this.v2 = Optional.of(v2); + this.v3 = Optional.empty(); + } - public SignalServiceAttachmentRemoteId(String v3) { - this.v2 = Optional.empty(); - this.v3 = Optional.of(v3); - } + public SignalServiceAttachmentRemoteId(String v3) { + this.v2 = Optional.empty(); + this.v3 = Optional.of(v3); + } - public Optional getV2() { - return v2; - } + public Optional getV2() { + return v2; + } - public Optional getV3() { - return v3; - } + public Optional getV3() { + return v3; + } - @Override - public String toString() { - if (v2.isPresent()) { - return v2.get().toString(); - } else { - return v3.get(); - } + @Override + public String toString() { + if (v2.isPresent()) { + return v2.get().toString(); + } else { + return v3.get(); } + } - public static SignalServiceAttachmentRemoteId from(AttachmentPointer attachmentPointer) throws InvalidMessageStructureException { - switch (attachmentPointer.getAttachmentIdentifierCase()) { - case CDNID: - return new SignalServiceAttachmentRemoteId(attachmentPointer.getCdnId()); - case CDNKEY: - return new SignalServiceAttachmentRemoteId(attachmentPointer.getCdnKey()); - case ATTACHMENTIDENTIFIER_NOT_SET: - throw new InvalidMessageStructureException("AttachmentPointer CDN location not set"); - } - return null; + public static SignalServiceAttachmentRemoteId from(AttachmentPointer attachmentPointer) throws InvalidMessageStructureException { + if (attachmentPointer.cdnKey != null) { + return new SignalServiceAttachmentRemoteId(attachmentPointer.cdnKey); + } else if (attachmentPointer.cdnId != null && attachmentPointer.cdnId > 0) { + return new SignalServiceAttachmentRemoteId(attachmentPointer.cdnId); + } else { + throw new InvalidMessageStructureException("AttachmentPointer CDN location not set"); } + } - /** - * Guesses that strings which contain values parseable to {@code long} should use an id-based - * CDN path. Otherwise, use key-based CDN path. - */ - public static SignalServiceAttachmentRemoteId from(String string) { - try { - return new SignalServiceAttachmentRemoteId(Long.parseLong(string)); - } catch (NumberFormatException e) { - return new SignalServiceAttachmentRemoteId(string); - } + /** + * Guesses that strings which contain values parseable to {@code long} should use an id-based + * CDN path. Otherwise, use key-based CDN path. + */ + public static SignalServiceAttachmentRemoteId from(String string) { + try { + return new SignalServiceAttachmentRemoteId(Long.parseLong(string)); + } catch (NumberFormatException e) { + return new SignalServiceAttachmentRemoteId(string); } + } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceDataMessage.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceDataMessage.kt index c635944916..c34876ab60 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceDataMessage.kt +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceDataMessage.kt @@ -11,11 +11,11 @@ import org.whispersystems.signalservice.api.messages.shared.SharedContact import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.util.OptionalUtil.asOptional import org.whispersystems.signalservice.api.util.OptionalUtil.emptyIfStringEmpty -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange +import org.whispersystems.signalservice.internal.push.BodyRange import java.util.LinkedList import java.util.Optional -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage.Payment as PaymentProto -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage.Quote as QuoteProto +import org.whispersystems.signalservice.internal.push.DataMessage.Payment as PaymentProto +import org.whispersystems.signalservice.internal.push.DataMessage.Quote as QuoteProto /** * Represents a decrypted Signal Service data message. diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceGroupV2.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceGroupV2.java index 7391fce2ba..32ca6a2457 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceGroupV2.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceGroupV2.java @@ -2,7 +2,10 @@ package org.whispersystems.signalservice.api.messages; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.groups.GroupMasterKey; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.api.util.Preconditions; +import org.whispersystems.signalservice.internal.push.GroupContextV2; + +import io.reactivex.rxjava3.annotations.NonNull; /** * Group information to include in SignalServiceMessages destined to v2 groups. @@ -25,21 +28,23 @@ public final class SignalServiceGroupV2 { /** * Creates a context model populated from a protobuf group V2 context. */ - public static SignalServiceGroupV2 fromProtobuf(SignalServiceProtos.GroupContextV2 groupContextV2) { + public static SignalServiceGroupV2 fromProtobuf(@NonNull GroupContextV2 groupContextV2) { + Preconditions.checkArgument(groupContextV2.masterKey == null || groupContextV2.revision == null); + GroupMasterKey masterKey; try { - masterKey = new GroupMasterKey(groupContextV2.getMasterKey().toByteArray()); + masterKey = new GroupMasterKey(groupContextV2.masterKey.toByteArray()); } catch (InvalidInputException e) { throw new AssertionError(e); } Builder builder = newBuilder(masterKey); - if (groupContextV2.hasGroupChange() && !groupContextV2.getGroupChange().isEmpty()) { - builder.withSignedGroupChange(groupContextV2.getGroupChange().toByteArray()); + if (groupContextV2.groupChange != null && groupContextV2.groupChange.size() > 0) { + builder.withSignedGroupChange(groupContextV2.groupChange.toByteArray()); } - return builder.withRevision(groupContextV2.getRevision()) + return builder.withRevision(groupContextV2.revision) .build(); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceStoryMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceStoryMessage.java index e9b5f5f96d..7f9e7eda91 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceStoryMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceStoryMessage.java @@ -1,25 +1,25 @@ package org.whispersystems.signalservice.api.messages; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.BodyRange; import java.util.List; import java.util.Optional; public class SignalServiceStoryMessage { - private final Optional profileKey; - private final Optional groupContext; - private final Optional fileAttachment; - private final Optional textAttachment; - private final Optional allowsReplies; - private final Optional> bodyRanges; + private final Optional profileKey; + private final Optional groupContext; + private final Optional fileAttachment; + private final Optional textAttachment; + private final Optional allowsReplies; + private final Optional> bodyRanges; private SignalServiceStoryMessage(byte[] profileKey, SignalServiceGroupV2 groupContext, SignalServiceAttachment fileAttachment, SignalServiceTextAttachment textAttachment, boolean allowsReplies, - List bodyRanges) + List bodyRanges) { this.profileKey = Optional.ofNullable(profileKey); this.groupContext = Optional.ofNullable(groupContext); @@ -33,7 +33,7 @@ public class SignalServiceStoryMessage { SignalServiceGroupV2 groupContext, SignalServiceAttachment fileAttachment, boolean allowsReplies, - List bodyRanges) + List bodyRanges) { return new SignalServiceStoryMessage(profileKey, groupContext, fileAttachment, null, allowsReplies, bodyRanges); } @@ -42,7 +42,7 @@ public class SignalServiceStoryMessage { SignalServiceGroupV2 groupContext, SignalServiceTextAttachment textAttachment, boolean allowsReplies, - List bodyRanges) + List bodyRanges) { return new SignalServiceStoryMessage(profileKey, groupContext, null, textAttachment, allowsReplies, bodyRanges); } @@ -67,7 +67,7 @@ public class SignalServiceStoryMessage { return allowsReplies; } - public Optional> getBodyRanges() { + public Optional> getBodyRanges() { return bodyRanges; } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/HangupMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/HangupMessage.java index ea373c1792..f876b118fa 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/HangupMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/HangupMessage.java @@ -1,7 +1,7 @@ package org.whispersystems.signalservice.api.messages.calls; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.CallMessage; public class HangupMessage { @@ -28,16 +28,16 @@ public class HangupMessage { } public enum Type { - NORMAL("normal", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_NORMAL), - ACCEPTED("accepted", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_ACCEPTED), - DECLINED("declined", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_DECLINED), - BUSY("busy", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_BUSY), - NEED_PERMISSION("need_permission", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_NEED_PERMISSION); + NORMAL("normal", CallMessage.Hangup.Type.HANGUP_NORMAL), + ACCEPTED("accepted", CallMessage.Hangup.Type.HANGUP_ACCEPTED), + DECLINED("declined", CallMessage.Hangup.Type.HANGUP_DECLINED), + BUSY("busy", CallMessage.Hangup.Type.HANGUP_BUSY), + NEED_PERMISSION("need_permission", CallMessage.Hangup.Type.HANGUP_NEED_PERMISSION); private final String code; - private final SignalServiceProtos.CallMessage.Hangup.Type protoType; + private final CallMessage.Hangup.Type protoType; - Type(String code, SignalServiceProtos.CallMessage.Hangup.Type protoType) { + Type(String code, CallMessage.Hangup.Type protoType) { this.code = code; this.protoType = protoType; } @@ -46,7 +46,7 @@ public class HangupMessage { return code; } - public SignalServiceProtos.CallMessage.Hangup.Type getProtoType() { + public CallMessage.Hangup.Type getProtoType() { return protoType; } @@ -60,7 +60,7 @@ public class HangupMessage { throw new IllegalArgumentException("Unexpected code: " + code); } - public static Type fromProto(SignalServiceProtos.CallMessage.Hangup.Type hangupType) { + public static Type fromProto(CallMessage.Hangup.Type hangupType) { for (Type type : Type.values()) { if (type.getProtoType().equals(hangupType)) { return type; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OfferMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OfferMessage.java index 0580dbee63..a1688b248e 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OfferMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OfferMessage.java @@ -1,7 +1,6 @@ package org.whispersystems.signalservice.api.messages.calls; - -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.CallMessage; public class OfferMessage { @@ -34,13 +33,13 @@ public class OfferMessage { } public enum Type { - AUDIO_CALL("audio_call", SignalServiceProtos.CallMessage.Offer.Type.OFFER_AUDIO_CALL), - VIDEO_CALL("video_call", SignalServiceProtos.CallMessage.Offer.Type.OFFER_VIDEO_CALL); + AUDIO_CALL("audio_call", CallMessage.Offer.Type.OFFER_AUDIO_CALL), + VIDEO_CALL("video_call", CallMessage.Offer.Type.OFFER_VIDEO_CALL); private final String code; - private final SignalServiceProtos.CallMessage.Offer.Type protoType; + private final CallMessage.Offer.Type protoType; - Type(String code, SignalServiceProtos.CallMessage.Offer.Type protoType) { + Type(String code, CallMessage.Offer.Type protoType) { this.code = code; this.protoType = protoType; } @@ -49,11 +48,11 @@ public class OfferMessage { return code; } - public SignalServiceProtos.CallMessage.Offer.Type getProtoType() { + public CallMessage.Offer.Type getProtoType() { return protoType; } - public static Type fromProto(SignalServiceProtos.CallMessage.Offer.Type offerType) { + public static Type fromProto(CallMessage.Offer.Type offerType) { for (Type type : Type.values()) { if (type.getProtoType().equals(offerType)) { return type; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OpaqueMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OpaqueMessage.java index d6dab0765f..2526705b93 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OpaqueMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OpaqueMessage.java @@ -1,6 +1,6 @@ package org.whispersystems.signalservice.api.messages.calls; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.CallMessage; public class OpaqueMessage { @@ -24,11 +24,11 @@ public class OpaqueMessage { DROPPABLE, HANDLE_IMMEDIATELY; - public SignalServiceProtos.CallMessage.Opaque.Urgency toProto() { + public CallMessage.Opaque.Urgency toProto() { if (this == HANDLE_IMMEDIATELY) { - return SignalServiceProtos.CallMessage.Opaque.Urgency.HANDLE_IMMEDIATELY; + return CallMessage.Opaque.Urgency.HANDLE_IMMEDIATELY; } - return SignalServiceProtos.CallMessage.Opaque.Urgency.DROPPABLE; + return CallMessage.Opaque.Urgency.DROPPABLE; } } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStream.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStream.java index 5694e1db63..4a57b1daf6 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStream.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStream.java @@ -15,7 +15,7 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.ContactDetails; import org.whispersystems.signalservice.internal.util.Util; import java.io.IOException; @@ -39,16 +39,16 @@ public class DeviceContactsInputStream extends ChunkedInputStream { byte[] detailsSerialized = new byte[(int) detailsLength]; Util.readFully(in, detailsSerialized); - SignalServiceProtos.ContactDetails details = SignalServiceProtos.ContactDetails.parseFrom(detailsSerialized); + ContactDetails details = ContactDetails.ADAPTER.decode(detailsSerialized); - if (!SignalServiceAddress.isValidAddress(details.getAci(), details.getNumber())) { + if (!SignalServiceAddress.isValidAddress(details.aci, details.number)) { throw new IOException("Missing contact address!"); } - SignalServiceAddress address = new SignalServiceAddress(ServiceId.parseOrThrow(details.getAci()), details.getNumber()); - Optional name = Optional.ofNullable(details.getName()); + SignalServiceAddress address = new SignalServiceAddress(ServiceId.parseOrThrow(details.aci), details.number); + Optional name = Optional.ofNullable(details.name); Optional avatar = Optional.empty(); - Optional color = details.hasColor() ? Optional.of(details.getColor()) : Optional.empty(); + Optional color = details.color != null ? Optional.of(details.color) : Optional.empty(); Optional verified = Optional.empty(); Optional profileKey = Optional.empty(); boolean blocked = false; @@ -56,29 +56,30 @@ public class DeviceContactsInputStream extends ChunkedInputStream { Optional inboxPosition = Optional.empty(); boolean archived = false; - if (details.hasAvatar()) { - long avatarLength = details.getAvatar().getLength(); + if (details.avatar != null) { + long avatarLength = details.avatar.length; InputStream avatarStream = new LimitedInputStream(in, avatarLength); - String avatarContentType = details.getAvatar().getContentType(); + String avatarContentType = details.avatar.contentType; avatar = Optional.of(new SignalServiceAttachmentStream(avatarStream, avatarContentType, avatarLength, Optional.empty(), false, false, false, null, null)); } - if (details.hasVerified()) { + if (details.verified != null) { try { - if (!SignalServiceAddress.isValidAddress(details.getVerified().getDestinationAci(), null)) { + if (!SignalServiceAddress.isValidAddress(details.verified.destinationAci, null)) { throw new InvalidMessageException("Missing Verified address!"); } - IdentityKey identityKey = new IdentityKey(details.getVerified().getIdentityKey().toByteArray(), 0); - SignalServiceAddress destination = new SignalServiceAddress(ServiceId.parseOrThrow(details.getVerified().getDestinationAci())); + + IdentityKey identityKey = new IdentityKey(details.verified.identityKey.toByteArray(), 0); + SignalServiceAddress destination = new SignalServiceAddress(ServiceId.parseOrThrow(details.verified.destinationAci)); VerifiedMessage.VerifiedState state; - switch (details.getVerified().getState()) { + switch (details.verified.state) { case VERIFIED: state = VerifiedMessage.VerifiedState.VERIFIED; break; case UNVERIFIED:state = VerifiedMessage.VerifiedState.UNVERIFIED; break; case DEFAULT: state = VerifiedMessage.VerifiedState.DEFAULT; break; - default: throw new InvalidMessageException("Unknown state: " + details.getVerified().getState()); + default: throw new InvalidMessageException("Unknown state: " + details.verified.state); } verified = Optional.of(new VerifiedMessage(destination, identityKey, state, System.currentTimeMillis())); @@ -88,24 +89,24 @@ public class DeviceContactsInputStream extends ChunkedInputStream { } } - if (details.hasProfileKey()) { + if (details.profileKey != null) { try { - profileKey = Optional.ofNullable(new ProfileKey(details.getProfileKey().toByteArray())); + profileKey = Optional.ofNullable(new ProfileKey(details.profileKey.toByteArray())); } catch (InvalidInputException e) { Log.w(TAG, "Invalid profile key ignored", e); } } - if (details.hasExpireTimer() && details.getExpireTimer() > 0) { - expireTimer = Optional.of(details.getExpireTimer()); + if (details.expireTimer != null && details.expireTimer > 0) { + expireTimer = Optional.of(details.expireTimer); } - if (details.hasInboxPosition()) { - inboxPosition = Optional.of(details.getInboxPosition()); + if (details.inboxPosition != null) { + inboxPosition = Optional.of(details.inboxPosition); } - blocked = details.getBlocked(); - archived = details.getArchived(); + blocked = details.blocked; + archived = details.archived; return new DeviceContact(address, name, avatar, color, verified, profileKey, blocked, expireTimer, inboxPosition, archived); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsOutputStream.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsOutputStream.java index 2cc1490fe5..3c32793338 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsOutputStream.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsOutputStream.java @@ -6,13 +6,14 @@ package org.whispersystems.signalservice.api.messages.multidevice; -import com.google.protobuf.ByteString; - -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.ContactDetails; +import org.whispersystems.signalservice.internal.push.Verified; import java.io.IOException; import java.io.OutputStream; +import okio.ByteString; + public class DeviceContactsOutputStream extends ChunkedOutputStream { public DeviceContactsOutputStream(OutputStream out) { @@ -35,65 +36,67 @@ public class DeviceContactsOutputStream extends ChunkedOutputStream { } private void writeContactDetails(DeviceContact contact) throws IOException { - SignalServiceProtos.ContactDetails.Builder contactDetails = SignalServiceProtos.ContactDetails.newBuilder(); + ContactDetails.Builder contactDetails = new ContactDetails.Builder(); - contactDetails.setAci(contact.getAddress().getServiceId().toString()); + contactDetails.aci(contact.getAddress().getServiceId().toString()); if (contact.getAddress().getNumber().isPresent()) { - contactDetails.setNumber(contact.getAddress().getNumber().get()); + contactDetails.number(contact.getAddress().getNumber().get()); } if (contact.getName().isPresent()) { - contactDetails.setName(contact.getName().get()); + contactDetails.name(contact.getName().get()); } if (contact.getAvatar().isPresent()) { - SignalServiceProtos.ContactDetails.Avatar.Builder avatarBuilder = SignalServiceProtos.ContactDetails.Avatar.newBuilder(); - avatarBuilder.setContentType(contact.getAvatar().get().getContentType()); - avatarBuilder.setLength((int)contact.getAvatar().get().getLength()); - contactDetails.setAvatar(avatarBuilder); + ContactDetails.Avatar.Builder avatarBuilder = new ContactDetails.Avatar.Builder(); + avatarBuilder.contentType(contact.getAvatar().get().getContentType()); + avatarBuilder.length((int) contact.getAvatar().get().getLength()); + contactDetails.avatar(avatarBuilder.build()); } if (contact.getColor().isPresent()) { - contactDetails.setColor(contact.getColor().get()); + contactDetails.color(contact.getColor().get()); } if (contact.getVerified().isPresent()) { - SignalServiceProtos.Verified.State state; + Verified.State state; switch (contact.getVerified().get().getVerified()) { - case VERIFIED: state = SignalServiceProtos.Verified.State.VERIFIED; break; - case UNVERIFIED: state = SignalServiceProtos.Verified.State.UNVERIFIED; break; - default: state = SignalServiceProtos.Verified.State.DEFAULT; break; + case VERIFIED: + state = Verified.State.VERIFIED; break; + case UNVERIFIED: + state = Verified.State.UNVERIFIED; break; + default: + state = Verified.State.DEFAULT; break; } - SignalServiceProtos.Verified.Builder verifiedBuilder = SignalServiceProtos.Verified.newBuilder() - .setIdentityKey(ByteString.copyFrom(contact.getVerified().get().getIdentityKey().serialize())) - .setDestinationAci(contact.getVerified().get().getDestination().getServiceId().toString()) - .setState(state); + Verified.Builder verifiedBuilder = new Verified.Builder() + .identityKey(ByteString.of(contact.getVerified().get().getIdentityKey().serialize())) + .destinationAci(contact.getVerified().get().getDestination().getServiceId().toString()) + .state(state); - contactDetails.setVerified(verifiedBuilder.build()); + contactDetails.verified(verifiedBuilder.build()); } if (contact.getProfileKey().isPresent()) { - contactDetails.setProfileKey(ByteString.copyFrom(contact.getProfileKey().get().serialize())); + contactDetails.profileKey(ByteString.of(contact.getProfileKey().get().serialize())); } if (contact.getExpirationTimer().isPresent()) { - contactDetails.setExpireTimer(contact.getExpirationTimer().get()); + contactDetails.expireTimer(contact.getExpirationTimer().get()); } if (contact.getInboxPosition().isPresent()) { - contactDetails.setInboxPosition(contact.getInboxPosition().get()); + contactDetails.inboxPosition(contact.getInboxPosition().get()); } - contactDetails.setBlocked(contact.isBlocked()); - contactDetails.setArchived(contact.isArchived()); + contactDetails.blocked(contact.isBlocked()); + contactDetails.archived(contact.isArchived()); - byte[] serializedContactDetails = contactDetails.build().toByteArray(); + byte[] serializedContactDetails = contactDetails.build().encode(); writeVarint32(serializedContactDetails.length); out.write(serializedContactDetails); } - } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceGroupsOutputStream.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceGroupsOutputStream.java deleted file mode 100644 index c596245c8b..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceGroupsOutputStream.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (C) 2014-2016 Open Whisper Systems - * - * Licensed according to the LICENSE file in this repository. - */ - -package org.whispersystems.signalservice.api.messages.multidevice; - -import com.google.protobuf.ByteString; - -import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupDetails; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -public class DeviceGroupsOutputStream extends ChunkedOutputStream { - - public DeviceGroupsOutputStream(OutputStream out) { - super(out); - } - - public void write(DeviceGroup group) throws IOException { - writeGroupDetails(group); - writeAvatarImage(group); - } - - public void close() throws IOException { - out.close(); - } - - private void writeAvatarImage(DeviceGroup contact) throws IOException { - if (contact.getAvatar().isPresent()) { - writeStream(contact.getAvatar().get().getInputStream()); - } - } - - private void writeGroupDetails(DeviceGroup group) throws IOException { - GroupDetails.Builder groupDetails = GroupDetails.newBuilder(); - groupDetails.setId(ByteString.copyFrom(group.getId())); - - if (group.getName().isPresent()) { - groupDetails.setName(group.getName().get()); - } - - if (group.getAvatar().isPresent()) { - GroupDetails.Avatar.Builder avatarBuilder = GroupDetails.Avatar.newBuilder(); - avatarBuilder.setContentType(group.getAvatar().get().getContentType()); - avatarBuilder.setLength((int)group.getAvatar().get().getLength()); - groupDetails.setAvatar(avatarBuilder); - } - - if (group.getExpirationTimer().isPresent()) { - groupDetails.setExpireTimer(group.getExpirationTimer().get()); - } - - if (group.getColor().isPresent()) { - groupDetails.setColor(group.getColor().get()); - } - - List members = new ArrayList<>(group.getMembers().size()); - List membersE164 = new ArrayList<>(group.getMembers().size()); - - for (SignalServiceAddress address : group.getMembers()) { - if (address.getNumber().isPresent()) { - membersE164.add(address.getNumber().get()); - - GroupDetails.Member.Builder builder = GroupDetails.Member.newBuilder(); - builder.setE164(address.getNumber().get()); - members.add(builder.build()); - } - } - - groupDetails.addAllMembers(members); - groupDetails.addAllMembersE164(membersE164); - groupDetails.setActive(group.isActive()); - groupDetails.setBlocked(group.isBlocked()); - groupDetails.setArchived(group.isArchived()); - - if (group.getInboxPosition().isPresent()) { - groupDetails.setInboxPosition(group.getInboxPosition().get()); - } - - byte[] serializedContactDetails = groupDetails.build().toByteArray(); - - writeVarint32(serializedContactDetails.length); - out.write(serializedContactDetails); - } - - -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/OutgoingPaymentMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/OutgoingPaymentMessage.java index eca07c2bfe..62b7fedbbe 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/OutgoingPaymentMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/OutgoingPaymentMessage.java @@ -1,14 +1,13 @@ package org.whispersystems.signalservice.api.messages.multidevice; -import com.google.protobuf.ByteString; - import org.whispersystems.signalservice.api.payments.Money; import org.whispersystems.signalservice.api.push.ServiceId; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; import java.util.List; import java.util.Optional; +import okio.ByteString; + public final class OutgoingPaymentMessage { private final Optional recipient; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/RequestMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/RequestMessage.java index 494ce43665..82e684039c 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/RequestMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/RequestMessage.java @@ -6,14 +6,14 @@ package org.whispersystems.signalservice.api.messages.multidevice; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.Request; +import org.whispersystems.signalservice.internal.push.SyncMessage.Request; public class RequestMessage { private final Request request; public static RequestMessage forType(Request.Type type) { - return new RequestMessage(Request.newBuilder().setType(type).build()); + return new RequestMessage(new Request.Builder().type(type).build()); } public RequestMessage(Request request) { @@ -25,23 +25,23 @@ public class RequestMessage { } public boolean isContactsRequest() { - return request.getType() == Request.Type.CONTACTS; + return request.type == Request.Type.CONTACTS; } public boolean isBlockedListRequest() { - return request.getType() == Request.Type.BLOCKED; + return request.type == Request.Type.BLOCKED; } public boolean isConfigurationRequest() { - return request.getType() == Request.Type.CONFIGURATION; + return request.type == Request.Type.CONFIGURATION; } public boolean isKeysRequest() { - return request.getType() == Request.Type.KEYS; + return request.type == Request.Type.KEYS; } public boolean isPniIdentityRequest() { - return request.getType() == Request.Type.PNI_IDENTITY; + return request.type == Request.Type.PNI_IDENTITY; } public boolean isUrgent() { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/SignalServiceSyncMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/SignalServiceSyncMessage.java index 2171b156d4..4555b6a024 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/SignalServiceSyncMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/SignalServiceSyncMessage.java @@ -6,11 +6,9 @@ package org.whispersystems.signalservice.api.messages.multidevice; - -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallLinkUpdate; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallLogEvent; +import org.whispersystems.signalservice.internal.push.SyncMessage.CallEvent; +import org.whispersystems.signalservice.internal.push.SyncMessage.CallLinkUpdate; +import org.whispersystems.signalservice.internal.push.SyncMessage.CallLogEvent; import java.util.LinkedList; import java.util.List; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/payments/MoneyProtobufUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/payments/MoneyProtobufUtil.java deleted file mode 100644 index 88e9eec7a3..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/payments/MoneyProtobufUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.whispersystems.signalservice.api.payments; - -import org.whispersystems.signalservice.api.util.Uint64RangeException; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; - -public final class MoneyProtobufUtil { - - public static SignalServiceProtos.DataMessage.Payment.Amount moneyToPaymentAmount(Money money) { - SignalServiceProtos.DataMessage.Payment.Amount.Builder builder = SignalServiceProtos.DataMessage.Payment.Amount.newBuilder(); - - if (money instanceof Money.MobileCoin) { - try { - builder.setMobileCoin(SignalServiceProtos.DataMessage.Payment.Amount.MobileCoin.newBuilder() - .setPicoMob(money.requireMobileCoin() - .toPicoMobUint64())); - } catch (Uint64RangeException e) { - throw new AssertionError(e); - } - } else { - throw new AssertionError(); - } - - return builder.build(); - } - - public static Money paymentAmountToMoney(SignalServiceProtos.DataMessage.Payment.Amount amount) throws UnsupportedCurrencyException { - switch (amount.getAmountCase()) { - case MOBILECOIN: - return Money.picoMobileCoin(amount.getMobileCoin().getPicoMob()); - case AMOUNT_NOT_SET: - default: - throw new UnsupportedCurrencyException(); - } - } -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt index 66eec56015..1b527eb3fd 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt @@ -1,13 +1,13 @@ package org.whispersystems.signalservice.api.push -import com.google.protobuf.ByteString +import okio.ByteString import org.signal.libsignal.protocol.ServiceId.InvalidServiceIdException import org.signal.libsignal.protocol.SignalProtocolAddress import org.signal.libsignal.protocol.logging.Log +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.util.UuidUtil -import java.lang.IllegalArgumentException import java.util.UUID -import kotlin.jvm.Throws import org.signal.libsignal.protocol.ServiceId as LibSignalServiceId import org.signal.libsignal.protocol.ServiceId.Aci as LibSignalAci import org.signal.libsignal.protocol.ServiceId.Pni as LibSignalPni @@ -75,7 +75,7 @@ sealed class ServiceId(val libSignalServiceId: LibSignalServiceId) { /** Parses a ServiceId serialized as a ByteString. Returns null if the ServiceId is invalid. */ @JvmStatic - fun parseOrNull(bytes: ByteString): ServiceId? = parseOrNull(bytes.toByteArray()) + fun parseOrNull(bytes: okio.ByteString): ServiceId? = parseOrNull(bytes.toByteArray()) /** Parses a ServiceId serialized as a string. Crashes if the ServiceId is invalid. */ @JvmStatic @@ -101,7 +101,7 @@ sealed class ServiceId(val libSignalServiceId: LibSignalServiceId) { fun toProtocolAddress(deviceId: Int): SignalProtocolAddress = SignalProtocolAddress(libSignalServiceId.toServiceIdString(), deviceId) - fun toByteString(): ByteString = ByteString.copyFrom(libSignalServiceId.toServiceIdBinary()) + fun toByteString(): ByteString = ByteString.of(*libSignalServiceId.toServiceIdBinary()) fun toByteArray(): ByteArray = libSignalServiceId.toServiceIdBinary() diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java index 65b66a51f0..98a6f3b2b6 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java @@ -1,12 +1,11 @@ package org.whispersystems.signalservice.api.push; -import com.google.protobuf.ByteString; - import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId.PNI; import java.util.Objects; -import java.util.UUID; + +import okio.ByteString; /** * Helper for dealing with [ServiceId] matching when you only care that either of your diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/AttachmentPointerUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/AttachmentPointerUtil.java index dd1a3eadee..28cabeed80 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/AttachmentPointerUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/AttachmentPointerUtil.java @@ -1,100 +1,102 @@ package org.whispersystems.signalservice.api.util; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.whispersystems.signalservice.api.InvalidMessageStructureException; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; -import org.whispersystems.signalservice.internal.push.SignalServiceProtos; +import org.whispersystems.signalservice.internal.push.AttachmentPointer; import org.whispersystems.util.FlagUtil; +import java.io.IOException; +import java.util.Objects; import java.util.Optional; +import okio.ByteString; + public final class AttachmentPointerUtil { - public static SignalServiceAttachmentPointer createSignalAttachmentPointer(byte[] pointer) throws InvalidMessageStructureException, InvalidProtocolBufferException { - return createSignalAttachmentPointer(SignalServiceProtos.AttachmentPointer.parseFrom(pointer)); + public static SignalServiceAttachmentPointer createSignalAttachmentPointer(byte[] pointer) throws InvalidMessageStructureException, IOException { + return createSignalAttachmentPointer(AttachmentPointer.ADAPTER.decode(pointer)); } - public static SignalServiceAttachmentPointer createSignalAttachmentPointer(SignalServiceProtos.AttachmentPointer pointer) throws InvalidMessageStructureException { - return new SignalServiceAttachmentPointer(pointer.getCdnNumber(), + public static SignalServiceAttachmentPointer createSignalAttachmentPointer(AttachmentPointer pointer) throws InvalidMessageStructureException { + return new SignalServiceAttachmentPointer(Objects.requireNonNull(pointer.cdnNumber), SignalServiceAttachmentRemoteId.from(pointer), - pointer.getContentType(), - pointer.getKey().toByteArray(), - pointer.hasSize() ? Optional.of(pointer.getSize()) : Optional.empty(), - pointer.hasThumbnail() ? Optional.of(pointer.getThumbnail().toByteArray()): Optional.empty(), - pointer.getWidth(), pointer.getHeight(), - pointer.hasDigest() ? Optional.of(pointer.getDigest().toByteArray()) : Optional.empty(), - pointer.hasIncrementalDigest() ? Optional.of(pointer.getIncrementalDigest().toByteArray()) : Optional.empty(), - pointer.hasFileName() ? Optional.of(pointer.getFileName()) : Optional.empty(), - (pointer.getFlags() & FlagUtil.toBinaryFlag(SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE_VALUE)) != 0, - (pointer.getFlags() & FlagUtil.toBinaryFlag(SignalServiceProtos.AttachmentPointer.Flags.BORDERLESS_VALUE)) != 0, - (pointer.getFlags() & FlagUtil.toBinaryFlag(SignalServiceProtos.AttachmentPointer.Flags.GIF_VALUE)) != 0, - pointer.hasCaption() ? Optional.of(pointer.getCaption()) : Optional.empty(), - pointer.hasBlurHash() ? Optional.of(pointer.getBlurHash()) : Optional.empty(), - pointer.hasUploadTimestamp() ? pointer.getUploadTimestamp() : 0); + pointer.contentType, + Objects.requireNonNull(pointer.key).toByteArray(), + pointer.size != null ? Optional.of(pointer.size) : Optional.empty(), + pointer.thumbnail != null ? Optional.of(pointer.thumbnail.toByteArray()): Optional.empty(), + pointer.width != null ? pointer.width : 0, + pointer.height != null ? pointer.height : 0, + pointer.digest != null ? Optional.of(pointer.digest.toByteArray()) : Optional.empty(), + pointer.incrementalDigest != null ? Optional.of(pointer.incrementalDigest.toByteArray()) : Optional.empty(), + pointer.fileName != null ? Optional.of(pointer.fileName) : Optional.empty(), + ((pointer.flags != null ? pointer.flags : 0) & FlagUtil.toBinaryFlag(AttachmentPointer.Flags.VOICE_MESSAGE.getValue())) != 0, + ((pointer.flags != null ? pointer.flags : 0) & FlagUtil.toBinaryFlag(AttachmentPointer.Flags.BORDERLESS.getValue())) != 0, + ((pointer.flags != null ? pointer.flags : 0) & FlagUtil.toBinaryFlag(AttachmentPointer.Flags.GIF.getValue())) != 0, + pointer.caption != null ? Optional.of(pointer.caption) : Optional.empty(), + pointer.blurHash != null ? Optional.of(pointer.blurHash) : Optional.empty(), + pointer.uploadTimestamp != null ? pointer.uploadTimestamp : 0); } - public static SignalServiceProtos.AttachmentPointer createAttachmentPointer(SignalServiceAttachmentPointer attachment) { - SignalServiceProtos.AttachmentPointer.Builder builder = SignalServiceProtos.AttachmentPointer.newBuilder() - .setCdnNumber(attachment.getCdnNumber()) - .setContentType(attachment.getContentType()) - .setKey(ByteString.copyFrom(attachment.getKey())) - .setDigest(ByteString.copyFrom(attachment.getDigest().get())) - .setSize(attachment.getSize().get()) - .setUploadTimestamp(attachment.getUploadTimestamp()); + public static AttachmentPointer createAttachmentPointer(SignalServiceAttachmentPointer attachment) { + AttachmentPointer.Builder builder = new AttachmentPointer.Builder() + .cdnNumber(attachment.getCdnNumber()) + .contentType(attachment.getContentType()) + .key(ByteString.of(attachment.getKey())) + .digest(ByteString.of(attachment.getDigest().get())) + .size(attachment.getSize().get()) + .uploadTimestamp(attachment.getUploadTimestamp()); if (attachment.getIncrementalDigest().isPresent()) { - builder.setIncrementalDigest(ByteString.copyFrom(attachment.getIncrementalDigest().get())); + builder.incrementalDigest(ByteString.of(attachment.getIncrementalDigest().get())); } if (attachment.getRemoteId().getV2().isPresent()) { - builder.setCdnId(attachment.getRemoteId().getV2().get()); + builder.cdnId(attachment.getRemoteId().getV2().get()); } if (attachment.getRemoteId().getV3().isPresent()) { - builder.setCdnKey(attachment.getRemoteId().getV3().get()); + builder.cdnKey(attachment.getRemoteId().getV3().get()); } if (attachment.getFileName().isPresent()) { - builder.setFileName(attachment.getFileName().get()); + builder.fileName(attachment.getFileName().get()); } if (attachment.getPreview().isPresent()) { - builder.setThumbnail(ByteString.copyFrom(attachment.getPreview().get())); + builder.thumbnail(ByteString.of(attachment.getPreview().get())); } if (attachment.getWidth() > 0) { - builder.setWidth(attachment.getWidth()); + builder.width(attachment.getWidth()); } if (attachment.getHeight() > 0) { - builder.setHeight(attachment.getHeight()); + builder.height(attachment.getHeight()); } int flags = 0; if (attachment.getVoiceNote()) { - flags |= FlagUtil.toBinaryFlag(SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE_VALUE); + flags |= FlagUtil.toBinaryFlag(AttachmentPointer.Flags.VOICE_MESSAGE.getValue()); } if (attachment.isBorderless()) { - flags |= FlagUtil.toBinaryFlag(SignalServiceProtos.AttachmentPointer.Flags.BORDERLESS_VALUE); + flags |= FlagUtil.toBinaryFlag(AttachmentPointer.Flags.BORDERLESS.getValue()); } if (attachment.isGif()) { - flags |= FlagUtil.toBinaryFlag(SignalServiceProtos.AttachmentPointer.Flags.GIF_VALUE); + flags |= FlagUtil.toBinaryFlag(AttachmentPointer.Flags.GIF.getValue()); } - builder.setFlags(flags); + builder.flags(flags); if (attachment.getCaption().isPresent()) { - builder.setCaption(attachment.getCaption().get()); + builder.caption(attachment.getCaption().get()); } if (attachment.getBlurHash().isPresent()) { - builder.setBlurHash(attachment.getBlurHash().get()); + builder.blurHash(attachment.getBlurHash().get()); } return builder.build(); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/UuidUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/UuidUtil.java index 28e81a2423..cb9333c089 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/UuidUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/UuidUtil.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.util; -import com.google.protobuf.ByteString; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; @@ -10,6 +8,8 @@ import java.util.Optional; import java.util.UUID; import java.util.regex.Pattern; +import okio.ByteString; + public final class UuidUtil { public static final UUID UNKNOWN_UUID = new UUID(0, 0); @@ -56,11 +56,7 @@ public final class UuidUtil { } public static ByteString toByteString(UUID uuid) { - return ByteString.copyFrom(toByteArray(uuid)); - } - - public static okio.ByteString toOkioByteString(UUID uuid) { - return okio.ByteString.of(toByteArray(uuid)); + return ByteString.of(toByteArray(uuid)); } public static UUID fromByteString(ByteString bytes) { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java index 3e60df6df1..a739e8972d 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java @@ -8,8 +8,6 @@ package org.whispersystems.signalservice.internal.push; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.MessageLite; import com.squareup.wire.Message; import org.signal.libsignal.protocol.InvalidKeyException; @@ -1386,10 +1384,10 @@ public class PushServiceSocket { public AttachmentDigest uploadGroupV2Avatar(byte[] avatarCipherText, AvatarUploadAttributes uploadAttributes) throws IOException { - return uploadToCdn0(AVATAR_UPLOAD_PATH, uploadAttributes.getAcl(), uploadAttributes.getKey(), - uploadAttributes.getPolicy(), uploadAttributes.getAlgorithm(), - uploadAttributes.getCredential(), uploadAttributes.getDate(), - uploadAttributes.getSignature(), + return uploadToCdn0(AVATAR_UPLOAD_PATH, uploadAttributes.acl, uploadAttributes.key, + uploadAttributes.policy, uploadAttributes.algorithm, + uploadAttributes.credential, uploadAttributes.date, + uploadAttributes.signature, new ByteArrayInputStream(avatarCipherText), "application/octet-stream", avatarCipherText.length, new NoCipherOutputStreamFactory(), @@ -1906,11 +1904,6 @@ public class PushServiceSocket { : null; } - private static RequestBody protobufRequestBody(MessageLite protobufBody) { - return protobufBody != null ? RequestBody.create(MediaType.parse("application/x-protobuf"), protobufBody.toByteArray()) - : null; - } - private static RequestBody protobufRequestBody(Message protobufBody) { return protobufBody != null ? RequestBody.create(MediaType.parse("application/x-protobuf"), protobufBody.encode()) : null; @@ -2620,7 +2613,7 @@ public class PushServiceSocket { } public Group getGroupsV2Group(GroupsV2AuthorizationString authorization) - throws NonSuccessfulResponseCodeException, PushNetworkException, InvalidProtocolBufferException, MalformedResponseException + throws NonSuccessfulResponseCodeException, PushNetworkException, IOException, MalformedResponseException { try (Response response = makeStorageRequest(authorization.toString(), GROUPSV2_GROUP, @@ -2628,12 +2621,12 @@ public class PushServiceSocket { null, GROUPS_V2_GET_CURRENT_HANDLER)) { - return Group.parseFrom(readBodyBytes(response)); + return Group.ADAPTER.decode(readBodyBytes(response)); } } public AvatarUploadAttributes getGroupsV2AvatarUploadForm(String authorization) - throws NonSuccessfulResponseCodeException, PushNetworkException, InvalidProtocolBufferException, MalformedResponseException + throws NonSuccessfulResponseCodeException, PushNetworkException, IOException, MalformedResponseException { try (Response response = makeStorageRequest(authorization, GROUPSV2_AVATAR_REQUEST, @@ -2641,12 +2634,12 @@ public class PushServiceSocket { null, NO_HANDLER)) { - return AvatarUploadAttributes.parseFrom(readBodyBytes(response)); + return AvatarUploadAttributes.ADAPTER.decode(readBodyBytes(response)); } } public GroupChange patchGroupsV2Group(GroupChange.Actions groupChange, String authorization, Optional groupLinkPassword) - throws NonSuccessfulResponseCodeException, PushNetworkException, InvalidProtocolBufferException, MalformedResponseException + throws NonSuccessfulResponseCodeException, PushNetworkException, IOException, MalformedResponseException { String path; @@ -2662,7 +2655,7 @@ public class PushServiceSocket { protobufRequestBody(groupChange), GROUPS_V2_PATCH_RESPONSE_HANDLER)) { - return GroupChange.parseFrom(readBodyBytes(response)); + return GroupChange.ADAPTER.decode(readBodyBytes(response)); } } @@ -2682,7 +2675,7 @@ public class PushServiceSocket { GroupChanges groupChanges; try (InputStream input = response.body().byteStream()) { - groupChanges = GroupChanges.parseFrom(input); + groupChanges = GroupChanges.ADAPTER.decode(input); } catch (IOException e) { throw new PushNetworkException(e); } @@ -2705,7 +2698,7 @@ public class PushServiceSocket { } public GroupJoinInfo getGroupJoinInfo(Optional groupLinkPassword, GroupsV2AuthorizationString authorization) - throws NonSuccessfulResponseCodeException, PushNetworkException, InvalidProtocolBufferException, MalformedResponseException + throws NonSuccessfulResponseCodeException, PushNetworkException, IOException, MalformedResponseException { String passwordParam = groupLinkPassword.map(Base64UrlSafe::encodeBytesWithoutPadding).orElse(""); try (Response response = makeStorageRequest(authorization.toString(), @@ -2714,12 +2707,12 @@ public class PushServiceSocket { null, GROUPS_V2_GET_JOIN_INFO_HANDLER)) { - return GroupJoinInfo.parseFrom(readBodyBytes(response)); + return GroupJoinInfo.ADAPTER.decode(readBodyBytes(response)); } } public GroupExternalCredential getGroupExternalCredential(GroupsV2AuthorizationString authorization) - throws NonSuccessfulResponseCodeException, PushNetworkException, InvalidProtocolBufferException, MalformedResponseException + throws NonSuccessfulResponseCodeException, PushNetworkException, IOException, MalformedResponseException { try (Response response = makeStorageRequest(authorization.toString(), GROUPSV2_TOKEN, @@ -2727,7 +2720,7 @@ public class PushServiceSocket { null, NO_HANDLER)) { - return GroupExternalCredential.parseFrom(readBodyBytes(response)); + return GroupExternalCredential.ADAPTER.decode(readBodyBytes(response)); } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializer.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializer.java deleted file mode 100644 index 0faec82f28..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializer.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.whispersystems.signalservice.internal.serialize; - - -import org.whispersystems.signalservice.api.push.ServiceId; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.internal.serialize.protos.AddressProto; - -import java.util.Optional; - -public final class SignalServiceAddressProtobufSerializer { - - private SignalServiceAddressProtobufSerializer() { - } - - public static AddressProto toProtobuf(SignalServiceAddress signalServiceAddress) { - AddressProto.Builder builder = AddressProto.newBuilder(); - - builder.setUuid(signalServiceAddress.getServiceId().toByteString()); - - if(signalServiceAddress.getNumber().isPresent()){ - builder.setE164(signalServiceAddress.getNumber().get()); - } - - return builder.build(); - } - - public static SignalServiceAddress fromProtobuf(AddressProto addressProto) { - ServiceId serviceId = ServiceId.parseOrThrow(addressProto.getUuid().toByteArray()); - Optional number = addressProto.hasE164() ? Optional.of(addressProto.getE164()) : Optional.empty(); - - return new SignalServiceAddress(serviceId, number); - } -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceMetadataProtobufSerializer.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceMetadataProtobufSerializer.java deleted file mode 100644 index 6de5bc1ffd..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/serialize/SignalServiceMetadataProtobufSerializer.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.whispersystems.signalservice.internal.serialize; - -import com.google.protobuf.ByteString; - -import org.whispersystems.signalservice.api.messages.SignalServiceMetadata; -import org.whispersystems.signalservice.internal.serialize.protos.MetadataProto; - -import java.util.Optional; - -public final class SignalServiceMetadataProtobufSerializer { - - private SignalServiceMetadataProtobufSerializer() { - } - - public static MetadataProto toProtobuf(SignalServiceMetadata metadata) { - MetadataProto.Builder builder = MetadataProto.newBuilder() - .setAddress(SignalServiceAddressProtobufSerializer.toProtobuf(metadata.getSender())) - .setSenderDevice(metadata.getSenderDevice()) - .setNeedsReceipt(metadata.isNeedsReceipt()) - .setTimestamp(metadata.getTimestamp()) - .setServerReceivedTimestamp(metadata.getServerReceivedTimestamp()) - .setServerDeliveredTimestamp(metadata.getServerDeliveredTimestamp()) - .setServerGuid(metadata.getServerGuid()) - .setDestinationUuid(metadata.getDestinationUuid()); - - if (metadata.getGroupId().isPresent()) { - builder.setGroupId(ByteString.copyFrom(metadata.getGroupId().get())); - } - - return builder.build(); - } - - public static SignalServiceMetadata fromProtobuf(MetadataProto metadata) { - return new SignalServiceMetadata(SignalServiceAddressProtobufSerializer.fromProtobuf(metadata.getAddress()), - metadata.getSenderDevice(), - metadata.getTimestamp(), - metadata.getServerReceivedTimestamp(), - metadata.getServerDeliveredTimestamp(), - metadata.getNeedsReceipt(), - metadata.getServerGuid(), - Optional.ofNullable(metadata.getGroupId()).map(ByteString::toByteArray), - metadata.getDestinationUuid()); - } -} diff --git a/libsignal/service/src/main/proto/DecryptedGroups.proto b/libsignal/service/src/main/protowire/DecryptedGroups.proto similarity index 100% rename from libsignal/service/src/main/proto/DecryptedGroups.proto rename to libsignal/service/src/main/protowire/DecryptedGroups.proto diff --git a/libsignal/service/src/main/proto/Groups.proto b/libsignal/service/src/main/protowire/Groups.proto similarity index 100% rename from libsignal/service/src/main/proto/Groups.proto rename to libsignal/service/src/main/protowire/Groups.proto diff --git a/libsignal/service/src/main/proto/InternalSerialization.proto b/libsignal/service/src/main/protowire/InternalSerialization.proto similarity index 100% rename from libsignal/service/src/main/proto/InternalSerialization.proto rename to libsignal/service/src/main/protowire/InternalSerialization.proto diff --git a/libsignal/service/src/main/proto/SignalService.proto b/libsignal/service/src/main/protowire/SignalService.proto similarity index 99% rename from libsignal/service/src/main/proto/SignalService.proto rename to libsignal/service/src/main/protowire/SignalService.proto index 11735b4f1b..f3386a72f5 100644 --- a/libsignal/service/src/main/proto/SignalService.proto +++ b/libsignal/service/src/main/protowire/SignalService.proto @@ -36,7 +36,7 @@ message Envelope { optional bool urgent = 14 [default = true]; reserved /*updatedPni*/ 15; // Not used presently, may be used in the future optional bool story = 16; - optional bytes reporting_token = 17; + optional bytes reportingToken = 17; // NEXT ID: 18 } @@ -122,7 +122,7 @@ message CallMessage { optional Busy busy = 5; reserved /* profileKey */ 6; optional Hangup hangup = 7; - optional bool multiRing = 8; + reserved /* multiRing */ 8; optional uint32 destinationDeviceId = 9; optional Opaque opaque = 10; } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtilTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtilTest.java index fe30501068..0c8fcb9efc 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtilTest.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtilTest.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Test; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.protos.groups.local.DecryptedPendingMember; @@ -13,21 +11,22 @@ import org.whispersystems.signalservice.internal.util.Util; import java.util.List; import java.util.UUID; +import okio.ByteString; + import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; import static java.util.Arrays.asList; public final class DecryptedGroupUtilTest { @Test public void can_extract_editor_uuid_from_decrypted_group_change() { - ACI aci = ACI.from(UUID.randomUUID()); - ByteString editor = aci.toByteString(); - DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder() - .setEditorServiceIdBytes(editor) + ACI aci = ACI.from(UUID.randomUUID()); + ByteString editor = aci.toByteString(); + DecryptedGroupChange groupChange = new DecryptedGroupChange.Builder() + .editorServiceIdBytes(editor) .build(); ServiceId parsed = DecryptedGroupUtil.editorServiceId(groupChange).get(); @@ -38,22 +37,22 @@ public final class DecryptedGroupUtilTest { @Test public void can_extract_uuid_from_decrypted_pending_member() { ACI aci = ACI.from(UUID.randomUUID()); - DecryptedPendingMember decryptedMember = DecryptedPendingMember.newBuilder() - .setServiceIdBytes(aci.toByteString()) + DecryptedPendingMember decryptedMember = new DecryptedPendingMember.Builder() + .serviceIdBytes(aci.toByteString()) .build(); - ServiceId parsed = ServiceId.parseOrNull(decryptedMember.getServiceIdBytes()); + ServiceId parsed = ServiceId.parseOrNull(decryptedMember.serviceIdBytes); assertEquals(aci, parsed); } @Test public void can_extract_uuid_from_bad_decrypted_pending_member() { - DecryptedPendingMember decryptedMember = DecryptedPendingMember.newBuilder() - .setServiceIdBytes(ByteString.copyFrom(Util.getSecretBytes(18))) + DecryptedPendingMember decryptedMember = new DecryptedPendingMember.Builder() + .serviceIdBytes(ByteString.of(Util.getSecretBytes(18))) .build(); - ServiceId parsed = ServiceId.parseOrNull(decryptedMember.getServiceIdBytes()); + ServiceId parsed = ServiceId.parseOrNull(decryptedMember.serviceIdBytes); assertNull(parsed); } @@ -62,23 +61,21 @@ public final class DecryptedGroupUtilTest { public void can_extract_uuids_for_all_pending_including_bad_entries() { ACI aci1 = ACI.from(UUID.randomUUID()); ACI aci2 = ACI.from(UUID.randomUUID()); - DecryptedPendingMember decryptedMember1 = DecryptedPendingMember.newBuilder() - .setServiceIdBytes(aci1.toByteString()) + DecryptedPendingMember decryptedMember1 = new DecryptedPendingMember.Builder() + .serviceIdBytes(aci1.toByteString()) .build(); - DecryptedPendingMember decryptedMember2 = DecryptedPendingMember.newBuilder() - .setServiceIdBytes(aci2.toByteString()) + DecryptedPendingMember decryptedMember2 = new DecryptedPendingMember.Builder() + .serviceIdBytes(aci2.toByteString()) .build(); - DecryptedPendingMember decryptedMember3 = DecryptedPendingMember.newBuilder() - .setServiceIdBytes(ByteString.copyFrom(Util.getSecretBytes(18))) + DecryptedPendingMember decryptedMember3 = new DecryptedPendingMember.Builder() + .serviceIdBytes(ByteString.of(Util.getSecretBytes(18))) .build(); - DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder() - .addNewPendingMembers(decryptedMember1) - .addNewPendingMembers(decryptedMember2) - .addNewPendingMembers(decryptedMember3) - .build(); + DecryptedGroupChange groupChange = new DecryptedGroupChange.Builder() + .newPendingMembers(asList(decryptedMember1, decryptedMember2, decryptedMember3)) + .build(); - List pendingUuids = DecryptedGroupUtil.pendingToServiceIdList(groupChange.getNewPendingMembersList()); + List pendingUuids = DecryptedGroupUtil.pendingToServiceIdList(groupChange.newPendingMembers); assertThat(pendingUuids, is(asList(aci1, aci2, ACI.UNKNOWN))); } @@ -87,21 +84,19 @@ public final class DecryptedGroupUtilTest { public void can_extract_uuids_for_all_deleted_pending_excluding_bad_entries() { ACI aci1 = ACI.from(UUID.randomUUID()); ACI aci2 = ACI.from(UUID.randomUUID()); - DecryptedPendingMemberRemoval decryptedMember1 = DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(aci1.toByteString()) + DecryptedPendingMemberRemoval decryptedMember1 = new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(aci1.toByteString()) .build(); - DecryptedPendingMemberRemoval decryptedMember2 = DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(aci2.toByteString()) + DecryptedPendingMemberRemoval decryptedMember2 = new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(aci2.toByteString()) .build(); - DecryptedPendingMemberRemoval decryptedMember3 = DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(ByteString.copyFrom(Util.getSecretBytes(18))) + DecryptedPendingMemberRemoval decryptedMember3 = new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(ByteString.of(Util.getSecretBytes(18))) .build(); - DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder() - .addDeletePendingMembers(decryptedMember1) - .addDeletePendingMembers(decryptedMember2) - .addDeletePendingMembers(decryptedMember3) - .build(); + DecryptedGroupChange groupChange = new DecryptedGroupChange.Builder() + .deletePendingMembers(asList(decryptedMember1, decryptedMember2, decryptedMember3)) + .build(); List removedUuids = DecryptedGroupUtil.removedPendingMembersServiceIdList(groupChange); @@ -112,11 +107,9 @@ public final class DecryptedGroupUtilTest { public void can_extract_uuids_for_all_deleted_members_excluding_bad_entries() { ACI aci1 = ACI.from(UUID.randomUUID()); ACI aci2 = ACI.from(UUID.randomUUID()); - DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder() - .addDeleteMembers(aci1.toByteString()) - .addDeleteMembers(aci2.toByteString()) - .addDeleteMembers(ByteString.copyFrom(Util.getSecretBytes(18))) - .build(); + DecryptedGroupChange groupChange = new DecryptedGroupChange.Builder() + .deleteMembers(asList(aci1.toByteString(), aci2.toByteString(), ByteString.of(Util.getSecretBytes(18)))) + .build(); List removedServiceIds = DecryptedGroupUtil.removedMembersServiceIdList(groupChange); diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java index 057ebc3eb5..bb1cafdc15 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_apply_Test.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Test; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.storageservice.protos.groups.AccessControl; @@ -21,8 +19,11 @@ import org.signal.storageservice.protos.groups.local.EnabledState; import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.util.Util; +import java.util.List; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertEquals; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.admin; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.asAdmin; @@ -54,14 +55,14 @@ public final class DecryptedGroupUtil_apply_Test { @Test public void apply_revision() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(9) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(9) + .build(), + new DecryptedGroupChange.Builder() + .revision(10) + .build()); - assertEquals(10, newGroup.getRevision()); + assertEquals(10, newGroup.revision); } @Test @@ -69,20 +70,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedMember member2 = member(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewMembers(member2) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newMembers(List.of(member2)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addMembers(member2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1, member2)) + .build(), newGroup); } @@ -91,21 +91,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedMember member2 = member(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addMembers(member2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewMembers(member2) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1, member2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newMembers(List.of(member2)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addMembers(member2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1, member2)) + .build(), newGroup); } @@ -116,21 +114,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member2a = member(member2Uuid, newProfileKey()); DecryptedMember member2b = member(member2Uuid, newProfileKey()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addMembers(member2a) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewMembers(member2b) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1, member2a)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newMembers(List.of(member2b)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addMembers(member2b) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1, member2b)) + .build(), newGroup); } @@ -139,20 +135,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedMember member2 = member(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .addMembers(member2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addDeleteMembers(member1.getAciBytes()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1, member2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .deleteMembers(List.of(member1.aciBytes)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(14) - .addMembers(member2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(14) + .members(List.of(member2)) + .build(), newGroup); } @@ -161,20 +156,18 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedMember member2 = member(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .addMembers(member2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addDeleteMembers(member1.getAciBytes()) - .addDeleteMembers(member2.getAciBytes()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1, member2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .deleteMembers(List.of(member1.aciBytes, member2.aciBytes)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(14) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(14) + .build(), newGroup); } @@ -183,19 +176,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedMember member2 = member(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addDeleteMembers(member2.getAciBytes()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .deleteMembers(List.of(member2.aciBytes)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .addMembers(member1) - .setRevision(14) - .build(), + assertEquals(new DecryptedGroup.Builder() + .members(List.of(member1)) + .revision(14) + .build(), newGroup); } @@ -204,22 +197,20 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedMember member2 = admin(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .addMembers(member2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder().setAciBytes(member1.getAciBytes()).setRole(Member.Role.ADMINISTRATOR)) - .addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder().setAciBytes(member2.getAciBytes()).setRole(Member.Role.DEFAULT)) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1, member2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .modifyMemberRoles(List.of(new DecryptedModifyMemberRole.Builder().aciBytes(member1.aciBytes).role(Member.Role.ADMINISTRATOR).build(), + new DecryptedModifyMemberRole.Builder().aciBytes(member2.aciBytes).role(Member.Role.DEFAULT).build())) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(14) - .addMembers(asAdmin(member1)) - .addMembers(asMember(member2)) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(14) + .members(List.of(asAdmin(member1), asMember(member2))) + .build(), newGroup); } @@ -228,33 +219,33 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedMember member2 = member(UUID.randomUUID()); - DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder() - .setRole(Member.Role.ADMINISTRATOR) - .setAciBytes(member2.getAciBytes()) - .build()) - .build()); + DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .modifyMemberRoles(List.of(new DecryptedModifyMemberRole.Builder() + .role(Member.Role.ADMINISTRATOR) + .aciBytes(member2.aciBytes) + .build())) + .build()); } @Test(expected = NotAbleToApplyGroupV2ChangeException.class) public void not_able_to_apply_modify_member_role_for_no_role() throws NotAbleToApplyGroupV2ChangeException { DecryptedMember member1 = member(UUID.randomUUID()); - DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder() - .setAciBytes(member1.getAciBytes()) - .build()) - .build()); + DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .modifyMemberRoles(List.of(new DecryptedModifyMemberRole.Builder() + .aciBytes(member1.aciBytes) + .build())) + .build()); } @Test @@ -266,21 +257,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member2a = member(UUID.randomUUID(), profileKey2a); DecryptedMember member2b = withProfileKey(member2a, profileKey2b); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .addMembers(member2a) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addModifiedProfileKeys(member2b) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1, member2a)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .modifiedProfileKeys(List.of(member2b)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(14) - .addMembers(member1) - .addMembers(member2b) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(14) + .members(List.of(member1, member2b)) + .build(), newGroup); } @@ -293,15 +282,14 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member2a = member(UUID.randomUUID(), profileKey2a); DecryptedMember member2b = member(UUID.randomUUID(), profileKey2b); - DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .addMembers(member2a) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addModifiedProfileKeys(member2b) - .build()); + DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1, member2a)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .modifiedProfileKeys(List.of(member2b)) + .build()); } @Test @@ -313,24 +301,24 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID(), profileKey1); DecryptedMember admin2a = admin(adminUuid, profileKey2a); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addMembers(member1) - .addMembers(admin2a) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addModifiedProfileKeys(DecryptedMember.newBuilder(DecryptedMember.newBuilder() - .setAciBytes(UuidUtil.toByteString(adminUuid)) - .build()) - .setProfileKey(ByteString.copyFrom(profileKey2b.serialize()))) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .members(List.of(member1, admin2a)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .modifiedProfileKeys(List.of(new DecryptedMember.Builder() + .aciBytes(UuidUtil.toByteString(adminUuid)) + .build() + .newBuilder() + .profileKey(ByteString.of(profileKey2b.serialize())) + .build())) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(14) - .addMembers(member1) - .addMembers(admin(adminUuid, profileKey2b)) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(14) + .members(List.of(member1, admin(adminUuid, profileKey2b))) + .build(), newGroup); } @@ -339,20 +327,20 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedPendingMember pending = pendingMember(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewPendingMembers(pending) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newPendingMembers(List.of(pending)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addPendingMembers(pending) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1)) + .pendingMembers(List.of(pending)) + .build(), newGroup); } @@ -361,21 +349,21 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedPendingMember pending = pendingMember(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addPendingMembers(pending) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewPendingMembers(pending) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .pendingMembers(List.of(pending)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newPendingMembers(List.of(pending)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addPendingMembers(pending) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1)) + .pendingMembers(List.of(pending)) + .build(), newGroup); } @@ -386,15 +374,14 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member2 = member(uuid2); DecryptedPendingMember pending2 = pendingMember(uuid2); - DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addMembers(member2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewPendingMembers(pending2) - .build()); + DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1, member2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newPendingMembers(List.of(pending2)) + .build()); } @Test @@ -403,22 +390,22 @@ public final class DecryptedGroupUtil_apply_Test { UUID pendingUuid = UUID.randomUUID(); DecryptedPendingMember pending = pendingMember(pendingUuid); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addPendingMembers(pending) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdCipherText(ProtoTestUtils.encrypt(pendingUuid)) - .build()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .pendingMembers(List.of(pending)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .deletePendingMembers(List.of(new DecryptedPendingMemberRemoval.Builder() + .serviceIdCipherText(ProtoTestUtils.encrypt(pendingUuid)) + .build())) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1)) + .build(), newGroup); } @@ -427,22 +414,22 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member1 = member(UUID.randomUUID()); UUID pendingUuid = UUID.randomUUID(); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdCipherText(ProtoTestUtils.encrypt(pendingUuid)) - .build()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .deletePendingMembers(List.of(new DecryptedPendingMemberRemoval.Builder() + .serviceIdCipherText(ProtoTestUtils.encrypt(pendingUuid)) + .build())) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .build(), - newGroup); + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1)) + .build(), + newGroup); } @Test @@ -453,39 +440,38 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedPendingMember pending2 = pendingMember(pending2Uuid); DecryptedMember member2 = member(pending2Uuid, profileKey2); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addPendingMembers(pending2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addPromotePendingMembers(member2) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .pendingMembers(List.of(pending2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .promotePendingMembers(List.of(member2)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addMembers(member2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1, member2)) + .build(), newGroup); } @Test(expected = NotAbleToApplyGroupV2ChangeException.class) public void cannot_promote_pending_member_if_not_in_group() throws NotAbleToApplyGroupV2ChangeException { - ProfileKey profileKey2 = randomProfileKey(); - DecryptedMember member1 = member(UUID.randomUUID()); - UUID pending2Uuid = UUID.randomUUID(); - DecryptedMember member2 = withProfileKey(admin(pending2Uuid), profileKey2); + ProfileKey profileKey2 = randomProfileKey(); + DecryptedMember member1 = member(UUID.randomUUID()); + UUID pending2Uuid = UUID.randomUUID(); + DecryptedMember member2 = withProfileKey(admin(pending2Uuid), profileKey2); - DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addPromotePendingMembers(member2) - .build()); + DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .promotePendingMembers(List.of(member2)) + .build()); } @Test @@ -502,26 +488,21 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member2 = member(pending2Uuid, profileKey2); DecryptedMember member3 = member(pending3Uuid, profileKey3); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addPendingMembers(pending2) - .addPendingMembers(pending3) - .addPendingMembers(pending4) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewMembers(member2) - .addNewMembers(member3) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .pendingMembers(List.of(pending2, pending3, pending4)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newMembers(List.of(member2, member3)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addMembers(member2) - .addMembers(member3) - .addPendingMembers(pending4) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1, member2, member3)) + .pendingMembers(List.of(pending4)) + .build(), newGroup); } @@ -539,215 +520,210 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedMember member2 = member(requesting2Uuid, profileKey2); DecryptedMember member3 = member(requesting3Uuid, profileKey3); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addRequestingMembers(requesting2) - .addRequestingMembers(requesting3) - .addRequestingMembers(requesting4) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewMembers(member2) - .addNewMembers(member3) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .requestingMembers(List.of(requesting2, requesting3, requesting4)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newMembers(List.of(member2, member3)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addMembers(member2) - .addMembers(member3) - .addRequestingMembers(requesting4) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1, member2, member3)) + .requestingMembers(List.of(requesting4)) + .build(), newGroup); } @Test public void title() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setTitle("Old title") - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewTitle(DecryptedString.newBuilder().setValue("New title").build()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .title("Old title") + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newTitle(new DecryptedString.Builder().value_("New title").build()) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setTitle("New title") - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .title("New title") + .build(), newGroup); } @Test public void description() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setDescription("Old description") - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewDescription(DecryptedString.newBuilder().setValue("New Description").build()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .description("Old description") + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newDescription(new DecryptedString.Builder().value_("New Description").build()) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setDescription("New Description") - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .description("New Description") + .build(), newGroup); } @Test public void isAnnouncementGroup() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setIsAnnouncementGroup(EnabledState.DISABLED) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewIsAnnouncementGroup(EnabledState.ENABLED) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .isAnnouncementGroup(EnabledState.DISABLED) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newIsAnnouncementGroup(EnabledState.ENABLED) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setIsAnnouncementGroup(EnabledState.ENABLED) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .isAnnouncementGroup(EnabledState.ENABLED) + .build(), newGroup); } @Test public void avatar() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setAvatar("https://cnd/oldavatar") - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewAvatar(DecryptedString.newBuilder().setValue("https://cnd/newavatar").build()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .avatar("https://cnd/oldavatar") + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newAvatar(new DecryptedString.Builder().value_("https://cnd/newavatar").build()) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setAvatar("https://cnd/newavatar") - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .avatar("https://cnd/newavatar") + .build(), newGroup); } @Test public void timer() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(100)) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewTimer(DecryptedTimer.newBuilder().setDuration(2000)) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .disappearingMessagesTimer(new DecryptedTimer.Builder().duration(100).build()) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newTimer(new DecryptedTimer.Builder().duration(2000).build()) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(2000)) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .disappearingMessagesTimer(new DecryptedTimer.Builder().duration(2000).build()) + .build(), newGroup); } @Test public void attribute_access() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.ADMINISTRATOR) - .setMembers(AccessControl.AccessRequired.MEMBER) - .build()) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewAttributeAccess(AccessControl.AccessRequired.MEMBER) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.ADMINISTRATOR) + .members(AccessControl.AccessRequired.MEMBER) + .build()) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newAttributeAccess(AccessControl.AccessRequired.MEMBER) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.MEMBER) - .setMembers(AccessControl.AccessRequired.MEMBER) - .build()) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.MEMBER) + .members(AccessControl.AccessRequired.MEMBER) + .build()) + .build(), newGroup); } @Test public void membership_access() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.ADMINISTRATOR) - .setMembers(AccessControl.AccessRequired.MEMBER) - .build()) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.ADMINISTRATOR) + .members(AccessControl.AccessRequired.MEMBER) + .build()) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.ADMINISTRATOR) - .setMembers(AccessControl.AccessRequired.ADMINISTRATOR) - .build()) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.ADMINISTRATOR) + .members(AccessControl.AccessRequired.ADMINISTRATOR) + .build()) + .build(), newGroup); } @Test public void change_both_access_levels() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.ADMINISTRATOR) - .setMembers(AccessControl.AccessRequired.MEMBER) - .build()) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewAttributeAccess(AccessControl.AccessRequired.MEMBER) - .setNewMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.ADMINISTRATOR) + .members(AccessControl.AccessRequired.MEMBER) + .build()) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newAttributeAccess(AccessControl.AccessRequired.MEMBER) + .newMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.MEMBER) - .setMembers(AccessControl.AccessRequired.ADMINISTRATOR) - .build()) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.MEMBER) + .members(AccessControl.AccessRequired.ADMINISTRATOR) + .build()) + .build(), newGroup); } @Test public void invite_link_access() throws NotAbleToApplyGroupV2ChangeException { - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.MEMBER) - .setMembers(AccessControl.AccessRequired.MEMBER) - .setAddFromInviteLink(AccessControl.AccessRequired.UNSATISFIABLE) - .build()) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.MEMBER) + .members(AccessControl.AccessRequired.MEMBER) + .addFromInviteLink(AccessControl.AccessRequired.UNSATISFIABLE) + .build()) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setAccessControl(AccessControl.newBuilder() - .setAttributes(AccessControl.AccessRequired.MEMBER) - .setMembers(AccessControl.AccessRequired.MEMBER) - .setAddFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR) - .build()) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .accessControl(new AccessControl.Builder() + .attributes(AccessControl.AccessRequired.MEMBER) + .members(AccessControl.AccessRequired.MEMBER) + .addFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR) + .build()) + .build(), newGroup); } @@ -756,20 +732,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedRequestingMember member1 = requestingMember(UUID.randomUUID()); DecryptedRequestingMember member2 = requestingMember(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addRequestingMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewRequestingMembers(member2) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .requestingMembers(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newRequestingMembers(List.of(member2)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addRequestingMembers(member1) - .addRequestingMembers(member2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .requestingMembers(List.of(member1, member2)) + .build(), newGroup); } @@ -778,20 +753,19 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedRequestingMember member1 = requestingMember(UUID.randomUUID()); DecryptedRequestingMember member2 = requestingMember(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addRequestingMembers(member1) - .addRequestingMembers(member2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addDeleteRequestingMembers(member1.getAciBytes()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .requestingMembers(List.of(member1, member2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .deleteRequestingMembers(List.of(member1.aciBytes)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(14) - .addRequestingMembers(member2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(14) + .requestingMembers(List.of(member2)) + .build(), newGroup); } @@ -807,28 +781,27 @@ public final class DecryptedGroupUtil_apply_Test { DecryptedRequestingMember member2 = requestingMember(uuid2, profileKey2); DecryptedRequestingMember member3 = requestingMember(uuid3, profileKey3); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addRequestingMembers(member1) - .addRequestingMembers(member2) - .addRequestingMembers(member3) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addPromoteRequestingMembers(DecryptedApproveMember.newBuilder() - .setRole(Member.Role.DEFAULT) - .setAciBytes(member1.getAciBytes())) - .addPromoteRequestingMembers(DecryptedApproveMember.newBuilder() - .setRole(Member.Role.ADMINISTRATOR) - .setAciBytes(member2.getAciBytes())) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .requestingMembers(List.of(member1, member2, member3)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .promoteRequestingMembers(List.of(new DecryptedApproveMember.Builder() + .role(Member.Role.DEFAULT) + .aciBytes(member1.aciBytes) + .build(), + new DecryptedApproveMember.Builder() + .role(Member.Role.ADMINISTRATOR) + .aciBytes(member2.aciBytes) + .build())) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(14) - .addMembers(member(uuid1, profileKey1)) - .addMembers(admin(uuid2, profileKey2)) - .addRequestingMembers(member3) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(14) + .members(List.of(member(uuid1, profileKey1), admin(uuid2, profileKey2))) + .requestingMembers(List.of(member3)) + .build(), newGroup); } @@ -837,101 +810,99 @@ public final class DecryptedGroupUtil_apply_Test { UUID uuid = UUID.randomUUID(); DecryptedRequestingMember member = requestingMember(uuid); - DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(13) - .addRequestingMembers(member) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(14) - .addPromoteRequestingMembers(DecryptedApproveMember.newBuilder() - .setAciBytes(member.getAciBytes())) - .build()); + DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(13) + .requestingMembers(List.of(member)) + .build(), + new DecryptedGroupChange.Builder() + .revision(14) + .promoteRequestingMembers(List.of(new DecryptedApproveMember.Builder().aciBytes(member.aciBytes).build())) + .build()); } @Test public void invite_link_password() throws NotAbleToApplyGroupV2ChangeException { - ByteString password1 = ByteString.copyFrom(Util.getSecretBytes(16)); - ByteString password2 = ByteString.copyFrom(Util.getSecretBytes(16)); + ByteString password1 = ByteString.of(Util.getSecretBytes(16)); + ByteString password2 = ByteString.of(Util.getSecretBytes(16)); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setInviteLinkPassword(password1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .setNewInviteLinkPassword(password2) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .inviteLinkPassword(password1) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newInviteLinkPassword(password2) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setInviteLinkPassword(password2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .inviteLinkPassword(password2) + .build(), newGroup); } @Test public void invite_link_password_not_changed() throws NotAbleToApplyGroupV2ChangeException { - ByteString password = ByteString.copyFrom(Util.getSecretBytes(16)); + ByteString password = ByteString.of(Util.getSecretBytes(16)); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .setInviteLinkPassword(password) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .inviteLinkPassword(password) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .setInviteLinkPassword(password) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .inviteLinkPassword(password) + .build(), newGroup); } - @Test public void apply_new_banned_member() throws NotAbleToApplyGroupV2ChangeException { DecryptedMember member1 = member(UUID.randomUUID()); DecryptedBannedMember banned = bannedMember(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewBannedMembers(banned) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newBannedMembers(List.of(banned)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addBannedMembers(banned) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1)) + .bannedMembers(List.of(banned)) + .build(), newGroup); } @Test public void apply_new_banned_member_already_banned() throws NotAbleToApplyGroupV2ChangeException { - DecryptedMember member1 = member(UUID.randomUUID()); - DecryptedBannedMember banned = bannedMember(UUID.randomUUID()); + DecryptedMember member1 = member(UUID.randomUUID()); + DecryptedBannedMember banned = bannedMember(UUID.randomUUID()); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addBannedMembers(banned) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addNewBannedMembers(banned) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .bannedMembers(List.of(banned)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .newBannedMembers(List.of(banned)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addBannedMembers(banned) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1)) + .bannedMembers(List.of(banned)) + .build(), newGroup); } @@ -941,49 +912,48 @@ public final class DecryptedGroupUtil_apply_Test { UUID bannedUuid = UUID.randomUUID(); DecryptedBannedMember banned = bannedMember(bannedUuid); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addBannedMembers(banned) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addDeleteBannedMembers(DecryptedBannedMember.newBuilder() - .setServiceIdBytes(UuidUtil.toByteString(bannedUuid)) - .build()) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .bannedMembers(List.of(banned)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .deleteBannedMembers(List.of(new DecryptedBannedMember.Builder() + .serviceIdBytes(UuidUtil.toByteString(bannedUuid)) + .build())) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1)) + .build(), newGroup); } @Test public void promote_pending_member_pni_aci() throws NotAbleToApplyGroupV2ChangeException { - ProfileKey profileKey2 = randomProfileKey(); - DecryptedMember member1 = member(UUID.randomUUID()); - UUID pending2Aci = UUID.randomUUID(); - UUID pending2Pni = UUID.randomUUID(); - DecryptedPendingMember pending2 = pendingMember(pending2Pni); - DecryptedMember member2 = pendingPniAciMember(pending2Aci, pending2Pni, profileKey2); + ProfileKey profileKey2 = randomProfileKey(); + DecryptedMember member1 = member(UUID.randomUUID()); + UUID pending2Aci = UUID.randomUUID(); + UUID pending2Pni = UUID.randomUUID(); + DecryptedPendingMember pending2 = pendingMember(pending2Pni); + DecryptedMember member2 = pendingPniAciMember(pending2Aci, pending2Pni, profileKey2); - DecryptedGroup newGroup = DecryptedGroupUtil.apply(DecryptedGroup.newBuilder() - .setRevision(10) - .addMembers(member1) - .addPendingMembers(pending2) - .build(), - DecryptedGroupChange.newBuilder() - .setRevision(11) - .addPromotePendingPniAciMembers(member2) - .build()); + DecryptedGroup newGroup = DecryptedGroupUtil.apply(new DecryptedGroup.Builder() + .revision(10) + .members(List.of(member1)) + .pendingMembers(List.of(pending2)) + .build(), + new DecryptedGroupChange.Builder() + .revision(11) + .promotePendingPniAciMembers(List.of(member2)) + .build()); - assertEquals(DecryptedGroup.newBuilder() - .setRevision(11) - .addMembers(member1) - .addMembers(member2) - .build(), + assertEquals(new DecryptedGroup.Builder() + .revision(11) + .members(List.of(member1, member2)) + .build(), newGroup); } } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_empty_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_empty_Test.java index 43c38cf4e5..6d320059a7 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_empty_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupUtil_empty_Test.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Test; import org.signal.storageservice.protos.groups.AccessControl; import org.signal.storageservice.protos.groups.local.DecryptedApproveMember; @@ -13,15 +11,18 @@ import org.signal.storageservice.protos.groups.local.DecryptedTimer; import org.signal.storageservice.protos.groups.local.EnabledState; import org.whispersystems.signalservice.api.util.UuidUtil; +import java.util.List; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.member; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.pendingMember; -import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.pendingPniAciMember; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.pendingMemberRemoval; +import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.pendingPniAciMember; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.promoteAdmin; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.randomProfileKey; import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber; @@ -43,14 +44,14 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void empty_change_set() { - assertTrue(DecryptedGroupUtil.changeIsEmpty(DecryptedGroupChange.newBuilder().build())); + assertTrue(DecryptedGroupUtil.changeIsEmpty(new DecryptedGroupChange.Builder().build())); } @Test public void not_empty_with_add_member_field_3() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addNewMembers(member(UUID.randomUUID())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newMembers(List.of(member(UUID.randomUUID()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -58,9 +59,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_delete_member_field_4() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addDeleteMembers(UuidUtil.toByteString(UUID.randomUUID())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .deleteMembers(List.of(UuidUtil.toByteString(UUID.randomUUID()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -68,9 +69,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_member_roles_field_5() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(promoteAdmin(UUID.randomUUID())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(promoteAdmin(UUID.randomUUID()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -78,9 +79,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_profile_keys_field_6() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addModifiedProfileKeys(member(UUID.randomUUID(), randomProfileKey())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .modifiedProfileKeys(List.of(member(UUID.randomUUID(), randomProfileKey()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertTrue(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -88,9 +89,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_add_pending_members_field_7() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addNewPendingMembers(pendingMember(UUID.randomUUID())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newPendingMembers(List.of(pendingMember(UUID.randomUUID()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -98,9 +99,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_delete_pending_members_field_8() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addDeletePendingMembers(pendingMemberRemoval(UUID.randomUUID())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .deletePendingMembers(List.of(pendingMemberRemoval(UUID.randomUUID()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -108,9 +109,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_promote_delete_pending_members_field_9() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addPromotePendingMembers(member(UUID.randomUUID())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .promotePendingMembers(List.of(member(UUID.randomUUID()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -118,9 +119,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_title_field_10() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewTitle(DecryptedString.newBuilder().setValue("New title")) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newTitle(new DecryptedString.Builder().value_("New title").build()) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -128,9 +129,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_avatar_field_11() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewAvatar(DecryptedString.newBuilder().setValue("New Avatar")) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newAvatar(new DecryptedString.Builder().value_("New Avatar").build()) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -138,9 +139,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_disappearing_message_timer_field_12() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewTimer(DecryptedTimer.newBuilder().setDuration(60)) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newTimer(new DecryptedTimer.Builder().duration(60).build()) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -148,9 +149,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_attributes_field_13() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -158,9 +159,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_member_access_field_14() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewMemberAccess(AccessControl.AccessRequired.MEMBER) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newMemberAccess(AccessControl.AccessRequired.MEMBER) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -168,9 +169,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_add_from_invite_link_access_field_15() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -178,9 +179,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_an_add_requesting_member_field_16() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(DecryptedRequestingMember.getDefaultInstance()) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(new DecryptedRequestingMember())) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -188,9 +189,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_a_delete_requesting_member_field_17() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addDeleteRequestingMembers(ByteString.copyFrom(new byte[16])) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .deleteRequestingMembers(List.of(ByteString.of(new byte[16]))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -198,9 +199,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_a_promote_requesting_member_field_18() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addPromoteRequestingMembers(DecryptedApproveMember.getDefaultInstance()) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .promoteRequestingMembers(List.of(new DecryptedApproveMember())) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -208,9 +209,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_a_new_invite_link_password_19() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewInviteLinkPassword(ByteString.copyFrom(new byte[16])) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newInviteLinkPassword(ByteString.of(new byte[16])) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -218,9 +219,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_description_field_20() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewDescription(DecryptedString.newBuilder().setValue("New description")) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newDescription(new DecryptedString.Builder().value_("New description").build()) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -228,9 +229,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_modify_announcement_field_21() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .setNewIsAnnouncementGroup(EnabledState.ENABLED) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newIsAnnouncementGroup(EnabledState.ENABLED) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -238,9 +239,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_add_banned_member_field_22() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addNewBannedMembers(DecryptedBannedMember.getDefaultInstance()) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .newBannedMembers(List.of(new DecryptedBannedMember())) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -248,9 +249,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_delete_banned_member_field_23() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addDeleteBannedMembers(DecryptedBannedMember.getDefaultInstance()) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .deleteBannedMembers(List.of(new DecryptedBannedMember())) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); @@ -258,9 +259,9 @@ public final class DecryptedGroupUtil_empty_Test { @Test public void not_empty_with_promote_pending_pni_aci_members_field_24() { - DecryptedGroupChange change = DecryptedGroupChange.newBuilder() - .addPromotePendingPniAciMembers(pendingPniAciMember(UUID.randomUUID(), UUID.randomUUID(), randomProfileKey())) - .build(); + DecryptedGroupChange change = new DecryptedGroupChange.Builder() + .promotePendingPniAciMembers(List.of(pendingPniAciMember(UUID.randomUUID(), UUID.randomUUID(), randomProfileKey()))) + .build(); assertFalse(DecryptedGroupUtil.changeIsEmpty(change)); assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change)); diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstructTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstructTest.java index 7cf4923721..a625bb299b 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstructTest.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeReconstructTest.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Test; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.storageservice.protos.groups.AccessControl; @@ -13,8 +11,11 @@ import org.signal.storageservice.protos.groups.local.EnabledState; import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.util.Util; +import java.util.List; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertEquals; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.admin; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.approveAdmin; @@ -48,208 +49,208 @@ public final class GroupChangeReconstructTest { @Test public void empty_to_empty() { - DecryptedGroup from = DecryptedGroup.newBuilder().build(); - DecryptedGroup to = DecryptedGroup.newBuilder().build(); + DecryptedGroup from = new DecryptedGroup.Builder().build(); + DecryptedGroup to = new DecryptedGroup.Builder().build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().build(), decryptedGroupChange); } @Test public void revision_set_to_the_target() { - DecryptedGroup from = DecryptedGroup.newBuilder().setRevision(10).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setRevision(20).build(); + DecryptedGroup from = new DecryptedGroup.Builder().revision(10).build(); + DecryptedGroup to = new DecryptedGroup.Builder().revision(20).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(20, decryptedGroupChange.getRevision()); + assertEquals(20, decryptedGroupChange.revision); } @Test public void title_change() { - DecryptedGroup from = DecryptedGroup.newBuilder().setTitle("A").build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setTitle("B").build(); + DecryptedGroup from = new DecryptedGroup.Builder().title("A").build(); + DecryptedGroup to = new DecryptedGroup.Builder().title("B").build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewTitle(DecryptedString.newBuilder().setValue("B")).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newTitle(new DecryptedString.Builder().value_("B").build()).build(), decryptedGroupChange); } @Test public void description_change() { - DecryptedGroup from = DecryptedGroup.newBuilder().setDescription("A").build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setDescription("B").build(); + DecryptedGroup from = new DecryptedGroup.Builder().description("A").build(); + DecryptedGroup to = new DecryptedGroup.Builder().description("B").build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewDescription(DecryptedString.newBuilder().setValue("B")).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newDescription(new DecryptedString.Builder().value_("B").build()).build(), decryptedGroupChange); } @Test public void announcement_group_change() { - DecryptedGroup from = DecryptedGroup.newBuilder().setIsAnnouncementGroup(EnabledState.DISABLED).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setIsAnnouncementGroup(EnabledState.ENABLED).build(); + DecryptedGroup from = new DecryptedGroup.Builder().isAnnouncementGroup(EnabledState.DISABLED).build(); + DecryptedGroup to = new DecryptedGroup.Builder().isAnnouncementGroup(EnabledState.ENABLED).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewIsAnnouncementGroup(EnabledState.ENABLED).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newIsAnnouncementGroup(EnabledState.ENABLED).build(), decryptedGroupChange); } @Test public void avatar_change() { - DecryptedGroup from = DecryptedGroup.newBuilder().setAvatar("A").build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setAvatar("B").build(); + DecryptedGroup from = new DecryptedGroup.Builder().avatar("A").build(); + DecryptedGroup to = new DecryptedGroup.Builder().avatar("B").build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewAvatar(DecryptedString.newBuilder().setValue("B")).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newAvatar(new DecryptedString.Builder().value_("B").build()).build(), decryptedGroupChange); } @Test public void timer_change() { - DecryptedGroup from = DecryptedGroup.newBuilder().setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(100)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(200)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().disappearingMessagesTimer(new DecryptedTimer.Builder().duration(100).build()).build(); + DecryptedGroup to = new DecryptedGroup.Builder().disappearingMessagesTimer(new DecryptedTimer.Builder().duration(200).build()).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewTimer(DecryptedTimer.newBuilder().setDuration(200)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newTimer(new DecryptedTimer.Builder().duration(200).build()).build(), decryptedGroupChange); } @Test public void access_control_change_attributes() { - DecryptedGroup from = DecryptedGroup.newBuilder().setAccessControl(AccessControl.newBuilder().setAttributes(AccessControl.AccessRequired.MEMBER)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setAccessControl(AccessControl.newBuilder().setAttributes(AccessControl.AccessRequired.ADMINISTRATOR)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().accessControl(new AccessControl.Builder().attributes(AccessControl.AccessRequired.MEMBER).build()).build(); + DecryptedGroup to = new DecryptedGroup.Builder().accessControl(new AccessControl.Builder().attributes(AccessControl.AccessRequired.ADMINISTRATOR).build()).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR).build(), decryptedGroupChange); } @Test public void access_control_change_membership() { - DecryptedGroup from = DecryptedGroup.newBuilder().setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.ADMINISTRATOR)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.MEMBER)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.ADMINISTRATOR).build()).build(); + DecryptedGroup to = new DecryptedGroup.Builder().accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.MEMBER).build()).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewMemberAccess(AccessControl.AccessRequired.MEMBER).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newMemberAccess(AccessControl.AccessRequired.MEMBER).build(), decryptedGroupChange); } @Test public void access_control_change_membership_and_attributes() { - DecryptedGroup from = DecryptedGroup.newBuilder().setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.MEMBER) - .setAttributes(AccessControl.AccessRequired.ADMINISTRATOR)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.ADMINISTRATOR) - .setAttributes(AccessControl.AccessRequired.MEMBER)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.MEMBER) + .attributes(AccessControl.AccessRequired.ADMINISTRATOR).build()).build(); + DecryptedGroup to = new DecryptedGroup.Builder().accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.ADMINISTRATOR) + .attributes(AccessControl.AccessRequired.MEMBER).build()).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().setNewMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .setNewAttributeAccess(AccessControl.AccessRequired.MEMBER).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .newAttributeAccess(AccessControl.AccessRequired.MEMBER).build(), decryptedGroupChange); } @Test public void new_member() { UUID uuidNew = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addMembers(member(uuidNew)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().build(); + DecryptedGroup to = new DecryptedGroup.Builder().members(List.of(member(uuidNew))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addNewMembers(member(uuidNew)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newMembers(List.of(member(uuidNew))).build(), decryptedGroupChange); } @Test public void removed_member() { UUID uuidOld = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().addMembers(member(uuidOld)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().build(); + DecryptedGroup from = new DecryptedGroup.Builder().members(List.of(member(uuidOld))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addDeleteMembers(UuidUtil.toByteString(uuidOld)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().deleteMembers(List.of(UuidUtil.toByteString(uuidOld))).build(), decryptedGroupChange); } @Test public void new_member_and_existing_member() { UUID uuidOld = UUID.randomUUID(); UUID uuidNew = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().addMembers(member(uuidOld)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addMembers(member(uuidOld)).addMembers(member(uuidNew)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().members(List.of(member(uuidOld))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().members(List.of(member(uuidOld), member(uuidNew))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addNewMembers(member(uuidNew)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newMembers(List.of(member(uuidNew))).build(), decryptedGroupChange); } @Test public void removed_member_and_remaining_member() { UUID uuidOld = UUID.randomUUID(); UUID uuidRemaining = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().addMembers(member(uuidOld)).addMembers(member(uuidRemaining)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addMembers(member(uuidRemaining)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().members(List.of(member(uuidOld), member(uuidRemaining))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().members(List.of(member(uuidRemaining))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addDeleteMembers(UuidUtil.toByteString(uuidOld)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().deleteMembers(List.of(UuidUtil.toByteString(uuidOld))).build(), decryptedGroupChange); } @Test public void new_member_by_invite() { UUID uuidNew = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().addPendingMembers(pendingMember(uuidNew)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addMembers(member(uuidNew)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().pendingMembers(List.of(pendingMember(uuidNew))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().members(List.of(member(uuidNew))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addPromotePendingMembers(member(uuidNew)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().promotePendingMembers(List.of(member(uuidNew))).build(), decryptedGroupChange); } @Test public void uninvited_member_by_invite() { UUID uuidNew = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().addPendingMembers(pendingMember(uuidNew)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().build(); + DecryptedGroup from = new DecryptedGroup.Builder().pendingMembers(List.of(pendingMember(uuidNew))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addDeletePendingMembers(pendingMemberRemoval(uuidNew)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().deletePendingMembers(List.of(pendingMemberRemoval(uuidNew))).build(), decryptedGroupChange); } @Test public void new_invite() { UUID uuidNew = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addPendingMembers(pendingMember(uuidNew)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().build(); + DecryptedGroup to = new DecryptedGroup.Builder().pendingMembers(List.of(pendingMember(uuidNew))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addNewPendingMembers(pendingMember(uuidNew)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newPendingMembers(List.of(pendingMember(uuidNew))).build(), decryptedGroupChange); } @Test public void to_admin() { UUID uuid = UUID.randomUUID(); ProfileKey profileKey = randomProfileKey(); - DecryptedGroup from = DecryptedGroup.newBuilder().addMembers(withProfileKey(member(uuid), profileKey)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addMembers(withProfileKey(admin(uuid), profileKey)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().members(List.of(withProfileKey(member(uuid), profileKey))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().members(List.of(withProfileKey(admin(uuid), profileKey))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addModifyMemberRoles(promoteAdmin(uuid)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().modifyMemberRoles(List.of(promoteAdmin(uuid))).build(), decryptedGroupChange); } @Test public void to_member() { UUID uuid = UUID.randomUUID(); ProfileKey profileKey = randomProfileKey(); - DecryptedGroup from = DecryptedGroup.newBuilder().addMembers(withProfileKey(admin(uuid), profileKey)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addMembers(withProfileKey(member(uuid), profileKey)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().members(List.of(withProfileKey(admin(uuid), profileKey))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().members(List.of(withProfileKey(member(uuid), profileKey))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addModifyMemberRoles(demoteAdmin(uuid)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().modifyMemberRoles(List.of(demoteAdmin(uuid))).build(), decryptedGroupChange); } @Test @@ -257,151 +258,154 @@ public final class GroupChangeReconstructTest { UUID uuid = UUID.randomUUID(); ProfileKey profileKey1 = randomProfileKey(); ProfileKey profileKey2 = randomProfileKey(); - DecryptedGroup from = DecryptedGroup.newBuilder().addMembers(withProfileKey(admin(uuid),profileKey1)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addMembers(withProfileKey(admin(uuid),profileKey2)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().members(List.of(withProfileKey(admin(uuid), profileKey1))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().members(List.of(withProfileKey(admin(uuid), profileKey2))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addModifiedProfileKeys(withProfileKey(admin(uuid),profileKey2)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().modifiedProfileKeys(List.of(withProfileKey(admin(uuid), profileKey2))).build(), decryptedGroupChange); } @Test public void new_invite_access() { - DecryptedGroup from = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder() - .setAddFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroup to = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder() - .setAddFromInviteLink(AccessControl.AccessRequired.UNSATISFIABLE)) - .build(); + DecryptedGroup from = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder() + .addFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR) + .build()) + .build(); + DecryptedGroup to = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder() + .addFromInviteLink(AccessControl.AccessRequired.UNSATISFIABLE) + .build()) + .build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder() - .setNewInviteLinkAccess(AccessControl.AccessRequired.UNSATISFIABLE) - .build(), + assertEquals(new DecryptedGroupChange.Builder() + .newInviteLinkAccess(AccessControl.AccessRequired.UNSATISFIABLE) + .build(), decryptedGroupChange); } @Test public void new_requesting_members() { - UUID member1 = UUID.randomUUID(); - ProfileKey profileKey1 = newProfileKey(); - DecryptedGroup from = DecryptedGroup.newBuilder() - .build(); - DecryptedGroup to = DecryptedGroup.newBuilder() - .addRequestingMembers(requestingMember(member1, profileKey1)) - .build(); + UUID member1 = UUID.randomUUID(); + ProfileKey profileKey1 = newProfileKey(); + DecryptedGroup from = new DecryptedGroup.Builder() + .build(); + DecryptedGroup to = new DecryptedGroup.Builder() + .requestingMembers(List.of(requestingMember(member1, profileKey1))) + .build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(requestingMember(member1, profileKey1)) - .build(), + assertEquals(new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(requestingMember(member1, profileKey1))) + .build(), decryptedGroupChange); } @Test public void new_requesting_members_ignores_existing_by_uuid() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - ProfileKey profileKey2 = newProfileKey(); - DecryptedGroup from = DecryptedGroup.newBuilder() - .addRequestingMembers(requestingMember(member1, newProfileKey())) - .build(); - DecryptedGroup to = DecryptedGroup.newBuilder() - .addRequestingMembers(requestingMember(member1, newProfileKey())) - .addRequestingMembers(requestingMember(member2, profileKey2)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + ProfileKey profileKey2 = newProfileKey(); + + DecryptedGroup from = new DecryptedGroup.Builder() + .requestingMembers(List.of(requestingMember(member1, newProfileKey()))) + .build(); + + DecryptedGroup to = new DecryptedGroup.Builder() + .requestingMembers(List.of(requestingMember(member1, newProfileKey()), requestingMember(member2, profileKey2))) + .build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(requestingMember(member2, profileKey2)) - .build(), + assertEquals(new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(requestingMember(member2, profileKey2))) + .build(), decryptedGroupChange); } @Test public void removed_requesting_members() { - UUID member1 = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder() - .addRequestingMembers(requestingMember(member1, newProfileKey())) - .build(); - DecryptedGroup to = DecryptedGroup.newBuilder() - .build(); + UUID member1 = UUID.randomUUID(); + DecryptedGroup from = new DecryptedGroup.Builder() + .requestingMembers(List.of(requestingMember(member1, newProfileKey()))) + .build(); + DecryptedGroup to = new DecryptedGroup.Builder() + .build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder() - .addDeleteRequestingMembers(UuidUtil.toByteString(member1)) - .build(), + assertEquals(new DecryptedGroupChange.Builder() + .deleteRequestingMembers(List.of(UuidUtil.toByteString(member1))) + .build(), decryptedGroupChange); } @Test public void promote_requesting_members() { - UUID member1 = UUID.randomUUID(); - ProfileKey profileKey1 = newProfileKey(); - UUID member2 = UUID.randomUUID(); - ProfileKey profileKey2 = newProfileKey(); - DecryptedGroup from = DecryptedGroup.newBuilder() - .addRequestingMembers(requestingMember(member1, profileKey1)) - .addRequestingMembers(requestingMember(member2, profileKey2)) - .build(); - DecryptedGroup to = DecryptedGroup.newBuilder() - .addMembers(member(member1, profileKey1)) - .addMembers(admin(member2, profileKey2)) - .build(); + UUID member1 = UUID.randomUUID(); + ProfileKey profileKey1 = newProfileKey(); + UUID member2 = UUID.randomUUID(); + ProfileKey profileKey2 = newProfileKey(); + DecryptedGroup from = new DecryptedGroup.Builder() + .requestingMembers(List.of(requestingMember(member1, profileKey1))) + .requestingMembers(List.of(requestingMember(member2, profileKey2))) + .build(); + DecryptedGroup to = new DecryptedGroup.Builder() + .members(List.of(member(member1, profileKey1))) + .members(List.of(admin(member2, profileKey2))) + .build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder() - .addPromoteRequestingMembers(approveMember(member1)) - .addPromoteRequestingMembers(approveAdmin(member2)) - .build(), + assertEquals(new DecryptedGroupChange.Builder() + .promoteRequestingMembers(List.of(approveMember(member1))) + .promoteRequestingMembers(List.of(approveAdmin(member2))) + .build(), decryptedGroupChange); } @Test public void new_invite_link_password() { - ByteString password1 = ByteString.copyFrom(Util.getSecretBytes(16)); - ByteString password2 = ByteString.copyFrom(Util.getSecretBytes(16)); - DecryptedGroup from = DecryptedGroup.newBuilder() - .setInviteLinkPassword(password1) - .build(); - DecryptedGroup to = DecryptedGroup.newBuilder() - .setInviteLinkPassword(password2) - .build(); + ByteString password1 = ByteString.of(Util.getSecretBytes(16)); + ByteString password2 = ByteString.of(Util.getSecretBytes(16)); + DecryptedGroup from = new DecryptedGroup.Builder() + .inviteLinkPassword(password1) + .build(); + DecryptedGroup to = new DecryptedGroup.Builder() + .inviteLinkPassword(password2) + .build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder() - .setNewInviteLinkPassword(password2) - .build(), + assertEquals(new DecryptedGroupChange.Builder() + .newInviteLinkPassword(password2) + .build(), decryptedGroupChange); } @Test public void new_banned_member() { UUID uuidNew = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().build(); - DecryptedGroup to = DecryptedGroup.newBuilder().addBannedMembers(bannedMember(uuidNew)).build(); + DecryptedGroup from = new DecryptedGroup.Builder().build(); + DecryptedGroup to = new DecryptedGroup.Builder().bannedMembers(List.of(bannedMember(uuidNew))).build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addNewBannedMembers(bannedMember(uuidNew)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().newBannedMembers(List.of(bannedMember(uuidNew))).build(), decryptedGroupChange); } @Test public void removed_banned_member() { UUID uuidOld = UUID.randomUUID(); - DecryptedGroup from = DecryptedGroup.newBuilder().addBannedMembers(bannedMember(uuidOld)).build(); - DecryptedGroup to = DecryptedGroup.newBuilder().build(); + DecryptedGroup from = new DecryptedGroup.Builder().bannedMembers(List.of(bannedMember(uuidOld))).build(); + DecryptedGroup to = new DecryptedGroup.Builder().build(); DecryptedGroupChange decryptedGroupChange = GroupChangeReconstruct.reconstructGroupChange(from, to); - assertEquals(DecryptedGroupChange.newBuilder().addDeleteBannedMembers(bannedMember(uuidOld)).build(), decryptedGroupChange); + assertEquals(new DecryptedGroupChange.Builder().deleteBannedMembers(List.of(bannedMember(uuidOld))).build(), decryptedGroupChange); } } \ No newline at end of file diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_changeIsEmpty_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_changeIsEmpty_Test.java index 994a21325e..24ff9e4f9a 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_changeIsEmpty_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_changeIsEmpty_Test.java @@ -3,6 +3,8 @@ package org.whispersystems.signalservice.api.groupsv2; import org.junit.Test; import org.signal.storageservice.protos.groups.GroupChange; +import java.util.List; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -25,203 +27,203 @@ public final class GroupChangeUtil_changeIsEmpty_Test { @Test public void empty_change_set() { - assertTrue(GroupChangeUtil.changeIsEmpty(GroupChange.Actions.newBuilder().build())); + assertTrue(GroupChangeUtil.changeIsEmpty(new GroupChange.Actions.Builder().build())); } @Test public void not_empty_with_add_member_field_3() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addAddMembers(GroupChange.Actions.AddMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .addMembers(List.of(new GroupChange.Actions.AddMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_delete_member_field_4() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addDeleteMembers(GroupChange.Actions.DeleteMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .deleteMembers(List.of(new GroupChange.Actions.DeleteMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_member_roles_field_5() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyMemberRoles(List.of(new GroupChange.Actions.ModifyMemberRoleAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_profile_keys_field_6() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addModifyMemberProfileKeys(GroupChange.Actions.ModifyMemberProfileKeyAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyMemberProfileKeys(List.of(new GroupChange.Actions.ModifyMemberProfileKeyAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_add_pending_members_field_7() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addAddPendingMembers(GroupChange.Actions.AddPendingMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .addPendingMembers(List.of(new GroupChange.Actions.AddPendingMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_delete_pending_members_field_8() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addDeletePendingMembers(GroupChange.Actions.DeletePendingMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .deletePendingMembers(List.of(new GroupChange.Actions.DeletePendingMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_promote_delete_pending_members_field_9() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .promotePendingMembers(List.of(new GroupChange.Actions.PromotePendingMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_title_field_10() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyTitle(GroupChange.Actions.ModifyTitleAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyTitle(new GroupChange.Actions.ModifyTitleAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_avatar_field_11() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyAvatar(new GroupChange.Actions.ModifyAvatarAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_disappearing_message_timer_field_12() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyDisappearingMessagesTimer(GroupChange.Actions.ModifyDisappearingMessagesTimerAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyDisappearingMessagesTimer(new GroupChange.Actions.ModifyDisappearingMessagesTimerAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_attributes_field_13() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyAttributesAccess(GroupChange.Actions.ModifyAttributesAccessControlAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyAttributesAccess(new GroupChange.Actions.ModifyAttributesAccessControlAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_member_access_field_14() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyMemberAccess(GroupChange.Actions.ModifyMembersAccessControlAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyMemberAccess(new GroupChange.Actions.ModifyMembersAccessControlAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_add_from_invite_link_field_15() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyAddFromInviteLinkAccess(GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyAddFromInviteLinkAccess(new GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_add_requesting_members_field_16() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .addRequestingMembers(List.of(new GroupChange.Actions.AddRequestingMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_delete_requesting_members_field_17() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addDeleteRequestingMembers(GroupChange.Actions.DeleteRequestingMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .deleteRequestingMembers(List.of(new GroupChange.Actions.DeleteRequestingMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_promote_requesting_members_field_18() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addPromoteRequestingMembers(GroupChange.Actions.PromoteRequestingMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .promoteRequestingMembers(List.of(new GroupChange.Actions.PromoteRequestingMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_promote_requesting_members_field_19() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyInviteLinkPassword(GroupChange.Actions.ModifyInviteLinkPasswordAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyInviteLinkPassword(new GroupChange.Actions.ModifyInviteLinkPasswordAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_description_field_20() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyDescription(GroupChange.Actions.ModifyDescriptionAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyDescription(new GroupChange.Actions.ModifyDescriptionAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_modify_description_field_21() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .setModifyAnnouncementsOnly(GroupChange.Actions.ModifyAnnouncementsOnlyAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .modifyAnnouncementsOnly(new GroupChange.Actions.ModifyAnnouncementsOnlyAction()) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_add_banned_member_field_22() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .addBannedMembers(List.of(new GroupChange.Actions.AddBannedMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_delete_banned_member_field_23() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .deleteBannedMembers(List.of(new GroupChange.Actions.DeleteBannedMemberAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } @Test public void not_empty_with_promote_pending_pni_aci_members_field_24() { - GroupChange.Actions actions = GroupChange.Actions.newBuilder() - .addPromotePendingPniAciMembers(GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.getDefaultInstance()) - .build(); + GroupChange.Actions actions = new GroupChange.Actions.Builder() + .promotePendingPniAciMembers(List.of(new GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction())) + .build(); assertFalse(GroupChangeUtil.changeIsEmpty(actions)); } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_Test.java index 6a3c99cca2..e2c4035261 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_Test.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Test; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.storageservice.protos.groups.AccessControl; @@ -18,8 +16,11 @@ import org.signal.storageservice.protos.groups.local.EnabledState; import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.util.Util; +import java.util.List; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.admin; @@ -67,7 +68,7 @@ public final class GroupChangeUtil_resolveConflict_Test { 24, maxFieldFound); } - /** + /** * Reflects over the generated protobuf class and ensures that no new fields have been added since we wrote this. *

* If we didn't, newly added fields would not be resolved by {@link GroupChangeUtil#resolveConflict(DecryptedGroup, DecryptedGroupChange, GroupChange.Actions)}. @@ -83,9 +84,9 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void empty_actions() { - GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(DecryptedGroup.newBuilder().build(), - DecryptedGroupChange.newBuilder().build(), - GroupChange.Actions.newBuilder().build()) + GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(new DecryptedGroup.Builder().build(), + new DecryptedGroupChange.Builder().build(), + new GroupChange.Actions.Builder().build()) .build(); assertTrue(GroupChangeUtil.changeIsEmpty(resolvedActions)); @@ -97,74 +98,69 @@ public final class GroupChangeUtil_resolveConflict_Test { UUID member2 = UUID.randomUUID(); UUID member3 = UUID.randomUUID(); ProfileKey profileKey2 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewMembers(member(member1)) - .addNewMembers(member(member2)) - .addNewMembers(member(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addAddMembers(GroupChange.Actions.AddMemberAction.newBuilder().setAdded(encryptedMember(member1, randomProfileKey()))) - .addAddMembers(GroupChange.Actions.AddMemberAction.newBuilder().setAdded(encryptedMember(member2, profileKey2))) - .addAddMembers(GroupChange.Actions.AddMemberAction.newBuilder().setAdded(encryptedMember(member3, randomProfileKey()))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder().members(List.of(member(member1), member(member3))).build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder().newMembers(List.of(member(member1), member(member2), member(member3))).build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .addMembers(List.of(new GroupChange.Actions.AddMemberAction.Builder().added(encryptedMember(member1, randomProfileKey())).build(), + new GroupChange.Actions.AddMemberAction.Builder().added(encryptedMember(member2, profileKey2)).build(), + new GroupChange.Actions.AddMemberAction.Builder().added(encryptedMember(member3, randomProfileKey())).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addAddMembers(GroupChange.Actions.AddMemberAction.newBuilder().setAdded(encryptedMember(member2, profileKey2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .addMembers(List.of(new GroupChange.Actions.AddMemberAction.Builder().added(encryptedMember(member2, profileKey2)).build())) + .build(); assertEquals(expected, resolvedActions); } @Test public void field_4__changes_to_remove_missing_members_are_excluded() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeleteMembers(UuidUtil.toByteString(member1)) - .addDeleteMembers(UuidUtil.toByteString(member2)) - .addDeleteMembers(UuidUtil.toByteString(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(encrypt(member1))) - .addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(encrypt(member3))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deleteMembers(List.of(UuidUtil.toByteString(member1), UuidUtil.toByteString(member2), UuidUtil.toByteString(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .deleteMembers(List.of(new GroupChange.Actions.DeleteMemberAction.Builder().deletedUserId(encrypt(member1)).build(), + new GroupChange.Actions.DeleteMemberAction.Builder().deletedUserId(encrypt(member2)).build(), + new GroupChange.Actions.DeleteMemberAction.Builder().deletedUserId(encrypt(member3)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .deleteMembers(List.of(new GroupChange.Actions.DeleteMemberAction.Builder().deletedUserId(encrypt(member2)).build())) + .build(); assertEquals(expected, resolvedActions); } @Test public void field_5__role_change_is_preserved() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(admin(member1)) - .addMembers(member(member2)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(demoteAdmin(member1)) - .addModifyMemberRoles(promoteAdmin(member2)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(encrypt(member1)).setRole(Member.Role.DEFAULT)) - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(encrypt(member2)).setRole(Member.Role.ADMINISTRATOR)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(admin(member1), member(member2), member(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(demoteAdmin(member1), promoteAdmin(member2))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyMemberRoles(List.of(new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encrypt(member1)).role(Member.Role.DEFAULT).build(), + new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encrypt(member2)).role(Member.Role.ADMINISTRATOR).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -173,196 +169,202 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_5__unnecessary_role_changes_removed() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - UUID memberNotInGroup = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(admin(member1)) - .addMembers(member(member2)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(promoteAdmin(member1)) - .addModifyMemberRoles(promoteAdmin(member2)) - .addModifyMemberRoles(demoteAdmin(member3)) - .addModifyMemberRoles(promoteAdmin(memberNotInGroup)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(encrypt(member1)).setRole(Member.Role.ADMINISTRATOR)) - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(encrypt(member2)).setRole(Member.Role.ADMINISTRATOR)) - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(encrypt(member3)).setRole(Member.Role.DEFAULT)) - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(encrypt(memberNotInGroup)).setRole(Member.Role.ADMINISTRATOR)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + UUID memberNotInGroup = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(admin(member1), member(member2), member(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(promoteAdmin(member1), promoteAdmin(member2), demoteAdmin(member3), promoteAdmin(memberNotInGroup))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyMemberRoles(List.of(new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encrypt(member1)).role(Member.Role.ADMINISTRATOR).build(), + new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encrypt(member2)).role(Member.Role.ADMINISTRATOR).build(), + new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encrypt(member3)).role(Member.Role.DEFAULT).build(), + new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encrypt(memberNotInGroup)).role(Member.Role.ADMINISTRATOR).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(encrypt(member2)).setRole(Member.Role.ADMINISTRATOR)) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .modifyMemberRoles(List.of(new GroupChange.Actions.ModifyMemberRoleAction.Builder().userId(encrypt(member2)).role(Member.Role.ADMINISTRATOR).build())) + .build(); assertEquals(expected, resolvedActions); } @Test public void field_6__profile_key_changes() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - UUID memberNotInGroup = UUID.randomUUID(); - ProfileKey profileKey1 = randomProfileKey(); - ProfileKey profileKey2 = randomProfileKey(); - ProfileKey profileKey3 = randomProfileKey(); - ProfileKey profileKey4 = randomProfileKey(); - ProfileKey profileKey2b = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1, profileKey1)) - .addMembers(member(member2, profileKey2)) - .addMembers(member(member3, profileKey3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addModifiedProfileKeys(member(member1, profileKey1)) - .addModifiedProfileKeys(member(member2, profileKey2b)) - .addModifiedProfileKeys(member(member3, profileKey3)) - .addModifiedProfileKeys(member(memberNotInGroup, profileKey4)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addModifyMemberProfileKeys(GroupChange.Actions.ModifyMemberProfileKeyAction.newBuilder().setPresentation(presentation(member1, profileKey1))) - .addModifyMemberProfileKeys(GroupChange.Actions.ModifyMemberProfileKeyAction.newBuilder().setPresentation(presentation(member2, profileKey2b))) - .addModifyMemberProfileKeys(GroupChange.Actions.ModifyMemberProfileKeyAction.newBuilder().setPresentation(presentation(member3, profileKey3))) - .addModifyMemberProfileKeys(GroupChange.Actions.ModifyMemberProfileKeyAction.newBuilder().setPresentation(presentation(memberNotInGroup, profileKey4))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + UUID memberNotInGroup = UUID.randomUUID(); + ProfileKey profileKey1 = randomProfileKey(); + ProfileKey profileKey2 = randomProfileKey(); + ProfileKey profileKey3 = randomProfileKey(); + ProfileKey profileKey4 = randomProfileKey(); + ProfileKey profileKey2b = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1, profileKey1), member(member2, profileKey2), member(member3, profileKey3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .modifiedProfileKeys(List.of(member(member1, profileKey1), member(member2, profileKey2b), member(member3, profileKey3), member(memberNotInGroup, profileKey4))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyMemberProfileKeys(List.of(new GroupChange.Actions.ModifyMemberProfileKeyAction.Builder().presentation(presentation(member1, profileKey1)).build(), + new GroupChange.Actions.ModifyMemberProfileKeyAction.Builder().presentation(presentation(member2, profileKey2b)).build(), + new GroupChange.Actions.ModifyMemberProfileKeyAction.Builder().presentation(presentation(member3, profileKey3)).build(), + new GroupChange.Actions.ModifyMemberProfileKeyAction.Builder().presentation(presentation(memberNotInGroup, profileKey4)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addModifyMemberProfileKeys(GroupChange.Actions.ModifyMemberProfileKeyAction.newBuilder().setPresentation(presentation(member2, profileKey2b))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .modifyMemberProfileKeys(List.of(new GroupChange.Actions.ModifyMemberProfileKeyAction.Builder().presentation(presentation(member2, profileKey2b)).build())) + .build(); assertEquals(expected, resolvedActions); } @Test public void field_7__add_pending_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - ProfileKey profileKey2 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addPendingMembers(pendingMember(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewPendingMembers(pendingMember(member1)) - .addNewPendingMembers(pendingMember(member2)) - .addNewPendingMembers(pendingMember(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + ProfileKey profileKey2 = randomProfileKey(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addAddPendingMembers(GroupChange.Actions.AddPendingMemberAction.newBuilder().setAdded(PendingMember.newBuilder().setMember(encryptedMember(member1, randomProfileKey())))) - .addAddPendingMembers(GroupChange.Actions.AddPendingMemberAction.newBuilder().setAdded(PendingMember.newBuilder().setMember(encryptedMember(member2, profileKey2)))) - .addAddPendingMembers(GroupChange.Actions.AddPendingMemberAction.newBuilder().setAdded(PendingMember.newBuilder().setMember(encryptedMember(member3, randomProfileKey())))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .pendingMembers(List.of(pendingMember(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newPendingMembers(List.of(pendingMember(member1), pendingMember(member2), pendingMember(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .addPendingMembers(List.of(new GroupChange.Actions.AddPendingMemberAction.Builder().added(new PendingMember.Builder().member(encryptedMember(member1, randomProfileKey())).build()).build(), + new GroupChange.Actions.AddPendingMemberAction.Builder().added(new PendingMember.Builder().member(encryptedMember(member2, profileKey2)).build()).build(), + new GroupChange.Actions.AddPendingMemberAction.Builder().added(new PendingMember.Builder().member(encryptedMember(member3, randomProfileKey())).build()).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addAddPendingMembers(GroupChange.Actions.AddPendingMemberAction.newBuilder().setAdded(PendingMember.newBuilder().setMember(encryptedMember(member2, profileKey2)))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .addPendingMembers(List.of(new GroupChange.Actions.AddPendingMemberAction.Builder().added(new PendingMember.Builder().member(encryptedMember(member2, profileKey2)).build()).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_8__delete_pending_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addPendingMembers(pendingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeletePendingMembers(pendingMemberRemoval(member1)) - .addDeletePendingMembers(pendingMemberRemoval(member2)) - .addDeletePendingMembers(pendingMemberRemoval(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addDeletePendingMembers(GroupChange.Actions.DeletePendingMemberAction.newBuilder().setDeletedUserId(encrypt(member1))) - .addDeletePendingMembers(GroupChange.Actions.DeletePendingMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .addDeletePendingMembers(GroupChange.Actions.DeletePendingMemberAction.newBuilder().setDeletedUserId(encrypt(member3))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .pendingMembers(List.of(pendingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deletePendingMembers(List.of(pendingMemberRemoval(member1), pendingMemberRemoval(member2), pendingMemberRemoval(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .deletePendingMembers(List.of(new GroupChange.Actions.DeletePendingMemberAction.Builder().deletedUserId(encrypt(member1)).build(), + new GroupChange.Actions.DeletePendingMemberAction.Builder().deletedUserId(encrypt(member2)).build(), + new GroupChange.Actions.DeletePendingMemberAction.Builder().deletedUserId(encrypt(member3)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addDeletePendingMembers(GroupChange.Actions.DeletePendingMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .deletePendingMembers(List.of(new GroupChange.Actions.DeletePendingMemberAction.Builder().deletedUserId(encrypt(member2)).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_9__promote_pending_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - ProfileKey profileKey2 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addPendingMembers(pendingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addPromotePendingMembers(member(member1)) - .addPromotePendingMembers(member(member2)) - .addPromotePendingMembers(member(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(presentation(member1, randomProfileKey()))) - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(presentation(member2, profileKey2))) - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(presentation(member3, randomProfileKey()))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + ProfileKey profileKey2 = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .pendingMembers(List.of(pendingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .promotePendingMembers(List.of(member(member1), member(member2), member(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .promotePendingMembers(List.of(new GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(presentation(member1, randomProfileKey())).build(), + new GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(presentation(member2, profileKey2)).build(), + new GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(presentation(member3, randomProfileKey())).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(presentation(member2, profileKey2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .promotePendingMembers(List.of(new GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(presentation(member2, profileKey2)).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_3_to_9__add_of_pending_member_converted_to_a_promote() { - UUID member1 = UUID.randomUUID(); - ProfileKey profileKey1 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addPendingMembers(pendingMember(member1)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewMembers(member(member1)) - .build(); + UUID member1 = UUID.randomUUID(); + ProfileKey profileKey1 = randomProfileKey(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addAddMembers(GroupChange.Actions.AddMemberAction.newBuilder().setAdded(encryptedMember(member1, profileKey1))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .pendingMembers(List.of(pendingMember(member1))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newMembers(List.of(member(member1))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .addMembers(List.of(new GroupChange.Actions.AddMemberAction.Builder().added(encryptedMember(member1, profileKey1)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(presentation(member1, profileKey1))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .promotePendingMembers(List.of(new GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(presentation(member1, profileKey1)).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_10__title_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setTitle("Existing title") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTitle(DecryptedString.newBuilder().setValue("New title").build()) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyTitle(GroupChange.Actions.ModifyTitleAction.newBuilder().setTitle(ByteString.copyFrom("New title encrypted".getBytes()))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .title("Existing title") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTitle(new DecryptedString.Builder().value_("New title").build()) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyTitle(new GroupChange.Actions.ModifyTitleAction.Builder().title(ByteString.of("New title encrypted".getBytes())).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -371,15 +373,17 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_10__no_title_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setTitle("Existing title") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTitle(DecryptedString.newBuilder().setValue("Existing title").build()) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyTitle(GroupChange.Actions.ModifyTitleAction.newBuilder().setTitle(ByteString.copyFrom("Existing title encrypted".getBytes()))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .title("Existing title") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTitle(new DecryptedString.Builder().value_("Existing title").build()) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyTitle(new GroupChange.Actions.ModifyTitleAction.Builder().title(ByteString.of("Existing title encrypted".getBytes())).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -388,15 +392,17 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_11__avatar_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAvatar("Existing avatar") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAvatar(DecryptedString.newBuilder().setValue("New avatar").build()) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder().setAvatar("New avatar possibly encrypted")) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .avatar("Existing avatar") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAvatar(new DecryptedString.Builder().value_("New avatar").build()) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyAvatar(new GroupChange.Actions.ModifyAvatarAction.Builder().avatar("New avatar possibly encrypted").build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -405,15 +411,17 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_11__no_avatar_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAvatar("Existing avatar") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAvatar(DecryptedString.newBuilder().setValue("Existing avatar").build()) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder().setAvatar("Existing avatar possibly encrypted")) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .avatar("Existing avatar") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAvatar(new DecryptedString.Builder().value_("Existing avatar").build()) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyAvatar(new GroupChange.Actions.ModifyAvatarAction.Builder().avatar("Existing avatar possibly encrypted").build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -422,15 +430,17 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_12__timer_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(123)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTimer(DecryptedTimer.newBuilder().setDuration(456)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyDisappearingMessagesTimer(GroupChange.Actions.ModifyDisappearingMessagesTimerAction.newBuilder().setTimer(ByteString.EMPTY)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .disappearingMessagesTimer(new DecryptedTimer.Builder().duration(123).build()) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTimer(new DecryptedTimer.Builder().duration(456).build()) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyDisappearingMessagesTimer(new GroupChange.Actions.ModifyDisappearingMessagesTimerAction.Builder().timer(ByteString.EMPTY).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -439,15 +449,17 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_12__no_timer_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(123)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTimer(DecryptedTimer.newBuilder().setDuration(123)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyDisappearingMessagesTimer(GroupChange.Actions.ModifyDisappearingMessagesTimerAction.newBuilder().setTimer(ByteString.EMPTY)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .disappearingMessagesTimer(new DecryptedTimer.Builder().duration(123).build()) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTimer(new DecryptedTimer.Builder().duration(123).build()) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyDisappearingMessagesTimer(new GroupChange.Actions.ModifyDisappearingMessagesTimerAction.Builder().timer(ByteString.EMPTY).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -456,15 +468,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_13__attribute_access_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setAttributes(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAttributeAccess(AccessControl.AccessRequired.MEMBER) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyAttributesAccess(GroupChange.Actions.ModifyAttributesAccessControlAction.newBuilder().setAttributesAccess(AccessControl.AccessRequired.MEMBER)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().attributes(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAttributeAccess(AccessControl.AccessRequired.MEMBER) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyAttributesAccess(new GroupChange.Actions.ModifyAttributesAccessControlAction.Builder().attributesAccess(AccessControl.AccessRequired.MEMBER).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -473,15 +485,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_13__no_attribute_access_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setAttributes(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyAttributesAccess(GroupChange.Actions.ModifyAttributesAccessControlAction.newBuilder().setAttributesAccess(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().attributes(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyAttributesAccess(new GroupChange.Actions.ModifyAttributesAccessControlAction.Builder().attributesAccess(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -490,15 +502,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_14__membership_access_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewMemberAccess(AccessControl.AccessRequired.MEMBER) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyMemberAccess(GroupChange.Actions.ModifyMembersAccessControlAction.newBuilder().setMembersAccess(AccessControl.AccessRequired.MEMBER)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newMemberAccess(AccessControl.AccessRequired.MEMBER) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyMemberAccess(new GroupChange.Actions.ModifyMembersAccessControlAction.Builder().membersAccess(AccessControl.AccessRequired.MEMBER).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -507,15 +519,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_14__no_membership_access_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyMemberAccess(GroupChange.Actions.ModifyMembersAccessControlAction.newBuilder().setMembersAccess(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyMemberAccess(new GroupChange.Actions.ModifyMembersAccessControlAction.Builder().membersAccess(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -524,15 +536,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_15__no_membership_access_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setAddFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyAddFromInviteLinkAccess(GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.newBuilder().setAddFromInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().addFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyAddFromInviteLinkAccess(new GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.Builder().addFromInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -541,154 +553,162 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_16__changes_to_add_requesting_members_when_full_members_are_removed() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - ProfileKey profileKey2 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(requestingMember(member1)) - .addNewRequestingMembers(requestingMember(member2)) - .addNewRequestingMembers(requestingMember(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member1, randomProfileKey()))) - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member2, profileKey2))) - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member3, randomProfileKey()))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + ProfileKey profileKey2 = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1), member(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(requestingMember(member1), requestingMember(member2), requestingMember(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .addRequestingMembers(List.of(new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member1, randomProfileKey())).build(), + new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member2, profileKey2)).build(), + new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member3, randomProfileKey())).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member2, profileKey2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .addRequestingMembers(List.of(new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member2, profileKey2)).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_16__changes_to_add_requesting_members_when_pending_are_promoted() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - ProfileKey profileKey1 = randomProfileKey(); - ProfileKey profileKey2 = randomProfileKey(); - ProfileKey profileKey3 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addPendingMembers(pendingMember(member1)) - .addPendingMembers(pendingMember(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(requestingMember(member1, profileKey1)) - .addNewRequestingMembers(requestingMember(member2, profileKey2)) - .addNewRequestingMembers(requestingMember(member3, profileKey3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member1, profileKey1))) - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member2, profileKey2))) - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member3, profileKey3))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + ProfileKey profileKey1 = randomProfileKey(); + ProfileKey profileKey2 = randomProfileKey(); + ProfileKey profileKey3 = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .pendingMembers(List.of(pendingMember(member1), pendingMember(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(requestingMember(member1, profileKey1), requestingMember(member2, profileKey2), requestingMember(member3, profileKey3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .addRequestingMembers(List.of(new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member1, profileKey1)).build(), + new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member2, profileKey2)).build(), + new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member3, profileKey3)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(presentation(member1, profileKey1))) - .addAddRequestingMembers(GroupChange.Actions.AddRequestingMemberAction.newBuilder().setAdded(encryptedRequestingMember(member2, profileKey2))) - .addPromotePendingMembers(GroupChange.Actions.PromotePendingMemberAction.newBuilder().setPresentation(presentation(member3, profileKey3))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .promotePendingMembers(List.of(new GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(presentation(member3, profileKey3)).build(), + new GroupChange.Actions.PromotePendingMemberAction.Builder().presentation(presentation(member1, profileKey1)).build())) + .addRequestingMembers(List.of(new GroupChange.Actions.AddRequestingMemberAction.Builder().added(encryptedRequestingMember(member2, profileKey2)).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_17__changes_to_remove_missing_requesting_members_are_excluded() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addRequestingMembers(requestingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeleteRequestingMembers(UuidUtil.toByteString(member1)) - .addDeleteRequestingMembers(UuidUtil.toByteString(member2)) - .addDeleteRequestingMembers(UuidUtil.toByteString(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addDeleteRequestingMembers(GroupChange.Actions.DeleteRequestingMemberAction.newBuilder().setDeletedUserId(encrypt(member1))) - .addDeleteRequestingMembers(GroupChange.Actions.DeleteRequestingMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .addDeleteRequestingMembers(GroupChange.Actions.DeleteRequestingMemberAction.newBuilder().setDeletedUserId(encrypt(member3))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .requestingMembers(List.of(requestingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deleteRequestingMembers(List.of(UuidUtil.toByteString(member1), UuidUtil.toByteString(member2), UuidUtil.toByteString(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .deleteRequestingMembers(List.of(new GroupChange.Actions.DeleteRequestingMemberAction.Builder().deletedUserId(encrypt(member1)).build(), + new GroupChange.Actions.DeleteRequestingMemberAction.Builder().deletedUserId(encrypt(member2)).build(), + new GroupChange.Actions.DeleteRequestingMemberAction.Builder().deletedUserId(encrypt(member3)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addDeleteRequestingMembers(GroupChange.Actions.DeleteRequestingMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .deleteRequestingMembers(List.of(new GroupChange.Actions.DeleteRequestingMemberAction.Builder().deletedUserId(encrypt(member2)).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_18__promote_requesting_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addRequestingMembers(requestingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addPromoteRequestingMembers(approveMember(member1)) - .addPromoteRequestingMembers(approveMember(member2)) - .addPromoteRequestingMembers(approveMember(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addPromoteRequestingMembers(GroupChange.Actions.PromoteRequestingMemberAction.newBuilder().setRole(Member.Role.DEFAULT).setUserId(UuidUtil.toByteString(member1))) - .addPromoteRequestingMembers(GroupChange.Actions.PromoteRequestingMemberAction.newBuilder().setRole(Member.Role.DEFAULT).setUserId(UuidUtil.toByteString(member2))) - .addPromoteRequestingMembers(GroupChange.Actions.PromoteRequestingMemberAction.newBuilder().setRole(Member.Role.DEFAULT).setUserId(UuidUtil.toByteString(member3))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .requestingMembers(List.of(requestingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .promoteRequestingMembers(List.of(approveMember(member1), approveMember(member2), approveMember(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .promoteRequestingMembers(List.of(new GroupChange.Actions.PromoteRequestingMemberAction.Builder().role(Member.Role.DEFAULT).userId(UuidUtil.toByteString(member1)).build(), + new GroupChange.Actions.PromoteRequestingMemberAction.Builder().role(Member.Role.DEFAULT).userId(UuidUtil.toByteString(member2)).build(), + new GroupChange.Actions.PromoteRequestingMemberAction.Builder().role(Member.Role.DEFAULT).userId(UuidUtil.toByteString(member3)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addPromoteRequestingMembers(GroupChange.Actions.PromoteRequestingMemberAction.newBuilder().setRole(Member.Role.DEFAULT).setUserId(UuidUtil.toByteString(member2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .promoteRequestingMembers(List.of(new GroupChange.Actions.PromoteRequestingMemberAction.Builder().role(Member.Role.DEFAULT).userId(UuidUtil.toByteString(member2)).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_19__password_change_is_kept() { - ByteString password1 = ByteString.copyFrom(Util.getSecretBytes(16)); - ByteString password2 = ByteString.copyFrom(Util.getSecretBytes(16)); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setInviteLinkPassword(password1) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewInviteLinkPassword(password2) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyInviteLinkPassword(GroupChange.Actions.ModifyInviteLinkPasswordAction.newBuilder().setInviteLinkPassword(password2)) - .build(); + ByteString password1 = ByteString.of(Util.getSecretBytes(16)); + ByteString password2 = ByteString.of(Util.getSecretBytes(16)); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .inviteLinkPassword(password1) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newInviteLinkPassword(password2) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyInviteLinkPassword(new GroupChange.Actions.ModifyInviteLinkPasswordAction.Builder().inviteLinkPassword(password2).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .setModifyInviteLinkPassword(GroupChange.Actions.ModifyInviteLinkPasswordAction.newBuilder().setInviteLinkPassword(password2)) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .modifyInviteLinkPassword(new GroupChange.Actions.ModifyInviteLinkPasswordAction.Builder().inviteLinkPassword(password2).build()) + .build(); assertEquals(expected, resolvedActions); } @Test public void field_20__description_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDescription("Existing title") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewDescription(DecryptedString.newBuilder().setValue("New title").build()) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyDescription(GroupChange.Actions.ModifyDescriptionAction.newBuilder().setDescription(ByteString.copyFrom("New title encrypted".getBytes()))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .description("Existing title") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newDescription(new DecryptedString.Builder().value_("New title").build()) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyDescription(new GroupChange.Actions.ModifyDescriptionAction.Builder().description(ByteString.of("New title encrypted".getBytes())).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -697,15 +717,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_20__no_description_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDescription("Existing title") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewDescription(DecryptedString.newBuilder().setValue("Existing title").build()) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyDescription(GroupChange.Actions.ModifyDescriptionAction.newBuilder().setDescription(ByteString.copyFrom("Existing title encrypted".getBytes()))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .description("Existing title") + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newDescription(new DecryptedString.Builder().value_("Existing title").build()) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyDescription(new GroupChange.Actions.ModifyDescriptionAction.Builder().description(ByteString.of("Existing title encrypted".getBytes())).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -714,15 +734,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_21__announcement_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setIsAnnouncementGroup(EnabledState.DISABLED) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewIsAnnouncementGroup(EnabledState.ENABLED) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyAnnouncementsOnly(GroupChange.Actions.ModifyAnnouncementsOnlyAction.newBuilder().setAnnouncementsOnly(true)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .isAnnouncementGroup(EnabledState.DISABLED) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newIsAnnouncementGroup(EnabledState.ENABLED) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyAnnouncementsOnly(new GroupChange.Actions.ModifyAnnouncementsOnlyAction.Builder().announcementsOnly(true).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -731,15 +751,15 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_21__announcement_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setIsAnnouncementGroup(EnabledState.ENABLED) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewIsAnnouncementGroup(EnabledState.ENABLED) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .setModifyAnnouncementsOnly(GroupChange.Actions.ModifyAnnouncementsOnlyAction.newBuilder().setAnnouncementsOnly(true)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .isAnnouncementGroup(EnabledState.ENABLED) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newIsAnnouncementGroup(EnabledState.ENABLED) + .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .modifyAnnouncementsOnly(new GroupChange.Actions.ModifyAnnouncementsOnlyAction.Builder().announcementsOnly(true).build()) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); @@ -749,59 +769,62 @@ public final class GroupChangeUtil_resolveConflict_Test { @Test public void field_22__add_banned_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addBannedMembers(bannedMember(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewBannedMembers(bannedMember(member1)) - .addNewBannedMembers(bannedMember(member2)) - .addNewBannedMembers(bannedMember(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encrypt(member1)))) - .addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encrypt(member2)))) - .addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encrypt(member3)))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .bannedMembers(List.of(bannedMember(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newBannedMembers(List.of(bannedMember(member1), bannedMember(member2), bannedMember(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .addBannedMembers(List.of(new GroupChange.Actions.AddBannedMemberAction.Builder().added(new BannedMember.Builder().userId(encrypt(member1)).build()).build(), + new GroupChange.Actions.AddBannedMemberAction.Builder().added(new BannedMember.Builder().userId(encrypt(member2)).build()).build(), + new GroupChange.Actions.AddBannedMemberAction.Builder().added(new BannedMember.Builder().userId(encrypt(member3)).build()).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encrypt(member1)))) - .addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encrypt(member2)))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .addBannedMembers(List.of(new GroupChange.Actions.AddBannedMemberAction.Builder().added(new BannedMember.Builder().userId(encrypt(member1)).build()).build(), + new GroupChange.Actions.AddBannedMemberAction.Builder().added(new BannedMember.Builder().userId(encrypt(member2)).build()).build())) + .build(); + assertEquals(expected, resolvedActions); } @Test public void field_23__delete_banned_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addBannedMembers(bannedMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeleteBannedMembers(bannedMember(member1)) - .addDeleteBannedMembers(bannedMember(member2)) - .addDeleteBannedMembers(bannedMember(member3)) - .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encrypt(member1))) - .addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encrypt(member3))) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .bannedMembers(List.of(bannedMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deleteBannedMembers(List.of(bannedMember(member1), bannedMember(member2), bannedMember(member3))) + .build(); + + GroupChange.Actions change = new GroupChange.Actions.Builder() + .deleteBannedMembers(List.of(new GroupChange.Actions.DeleteBannedMemberAction.Builder().deletedUserId(encrypt(member1)).build(), + new GroupChange.Actions.DeleteBannedMemberAction.Builder().deletedUserId(encrypt(member2)).build(), + new GroupChange.Actions.DeleteBannedMemberAction.Builder().deletedUserId(encrypt(member3)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encrypt(member2))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .deleteBannedMembers(List.of(new GroupChange.Actions.DeleteBannedMemberAction.Builder().deletedUserId(encrypt(member2)).build())) + .build(); + assertEquals(expected, resolvedActions); } @@ -810,25 +833,25 @@ public final class GroupChangeUtil_resolveConflict_Test { DecryptedMember member1 = pendingPniAciMember(UUID.randomUUID(), UUID.randomUUID(), randomProfileKey()); DecryptedMember member2 = pendingPniAciMember(UUID.randomUUID(), UUID.randomUUID(), randomProfileKey()); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(UuidUtil.fromByteString(member1.getAciBytes()))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(UuidUtil.fromByteString(member1.aciBytes)))) + .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addPromotePendingPniAciMembers(pendingPniAciMember(member1.getAciBytes(), member1.getPniBytes(), member1.getProfileKey())) - .addPromotePendingPniAciMembers(pendingPniAciMember(member2.getAciBytes(), member2.getPniBytes(), member2.getProfileKey())) - .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .promotePendingPniAciMembers(List.of(pendingPniAciMember(member1.aciBytes, member1.pniBytes, member1.profileKey), + pendingPniAciMember(member2.aciBytes, member2.pniBytes, member2.profileKey))) + .build(); - GroupChange.Actions change = GroupChange.Actions.newBuilder() - .addPromotePendingPniAciMembers(GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.newBuilder().setPresentation(presentation(member1.getPniBytes(), member1.getProfileKey()))) - .addPromotePendingPniAciMembers(GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.newBuilder().setPresentation(presentation(member2.getPniBytes(), member2.getProfileKey()))) - .build(); + GroupChange.Actions change = new GroupChange.Actions.Builder() + .promotePendingPniAciMembers(List.of(new GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.Builder().presentation(presentation(member1.pniBytes, member1.profileKey)).build(), + new GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.Builder().presentation(presentation(member2.pniBytes, member2.profileKey)).build())) + .build(); GroupChange.Actions resolvedActions = GroupChangeUtil.resolveConflict(groupState, decryptedChange, change).build(); - GroupChange.Actions expected = GroupChange.Actions.newBuilder() - .addPromotePendingPniAciMembers(GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.newBuilder().setPresentation(presentation(member2.getPniBytes(), member2.getProfileKey()))) - .build(); + GroupChange.Actions expected = new GroupChange.Actions.Builder() + .promotePendingPniAciMembers(List.of(new GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.Builder().presentation(presentation(member2.pniBytes, member2.profileKey)).build())) + .build(); assertEquals(expected, resolvedActions); } } \ No newline at end of file diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_decryptedOnly_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_decryptedOnly_Test.java index 6935876d87..9f4fbdb680 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_decryptedOnly_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupChangeUtil_resolveConflict_decryptedOnly_Test.java @@ -1,11 +1,8 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Test; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.storageservice.protos.groups.AccessControl; -import org.signal.storageservice.protos.groups.GroupChange; import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.protos.groups.local.DecryptedMember; @@ -15,8 +12,11 @@ import org.signal.storageservice.protos.groups.local.EnabledState; import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.util.Util; +import java.util.List; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.admin; @@ -27,7 +27,6 @@ import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.membe import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.pendingMember; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.pendingMemberRemoval; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.pendingPniAciMember; -import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.presentation; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.promoteAdmin; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.randomProfileKey; import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.requestingMember; @@ -64,64 +63,63 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_3__changes_to_add_existing_members_are_excluded() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewMembers(member(member1)) - .addNewMembers(member(member2)) - .addNewMembers(member(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1), member(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newMembers(List.of(member(member1), member(member2), member(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addNewMembers(member(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .newMembers(List.of(member(member2))) + .build(); + assertEquals(expected, resolvedChanges); } @Test public void field_4__changes_to_remove_missing_members_are_excluded() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeleteMembers(UuidUtil.toByteString(member1)) - .addDeleteMembers(UuidUtil.toByteString(member2)) - .addDeleteMembers(UuidUtil.toByteString(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deleteMembers(List.of(UuidUtil.toByteString(member1), UuidUtil.toByteString(member2), UuidUtil.toByteString(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addDeleteMembers(UuidUtil.toByteString(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .deleteMembers(List.of(UuidUtil.toByteString(member2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_5__role_change_is_preserved() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(admin(member1)) - .addMembers(member(member2)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(demoteAdmin(member1)) - .addModifyMemberRoles(promoteAdmin(member2)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(admin(member1), member(member2), member(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(demoteAdmin(member1), promoteAdmin(member2))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -130,163 +128,160 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_5__unnecessary_role_changes_removed() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - UUID memberNotInGroup = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(admin(member1)) - .addMembers(member(member2)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(promoteAdmin(member1)) - .addModifyMemberRoles(promoteAdmin(member2)) - .addModifyMemberRoles(demoteAdmin(member3)) - .addModifyMemberRoles(promoteAdmin(memberNotInGroup)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + UUID memberNotInGroup = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(admin(member1), member(member2), member(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(promoteAdmin(member1), promoteAdmin(member2), demoteAdmin(member3), promoteAdmin(memberNotInGroup))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(promoteAdmin(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(promoteAdmin(member2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_6__profile_key_changes() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - UUID memberNotInGroup = UUID.randomUUID(); - ProfileKey profileKey1 = randomProfileKey(); - ProfileKey profileKey2 = randomProfileKey(); - ProfileKey profileKey3 = randomProfileKey(); - ProfileKey profileKey4 = randomProfileKey(); - ProfileKey profileKey2b = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1, profileKey1)) - .addMembers(member(member2, profileKey2)) - .addMembers(member(member3, profileKey3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addModifiedProfileKeys(member(member1, profileKey1)) - .addModifiedProfileKeys(member(member2, profileKey2b)) - .addModifiedProfileKeys(member(member3, profileKey3)) - .addModifiedProfileKeys(member(memberNotInGroup, profileKey4)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + UUID memberNotInGroup = UUID.randomUUID(); + ProfileKey profileKey1 = randomProfileKey(); + ProfileKey profileKey2 = randomProfileKey(); + ProfileKey profileKey3 = randomProfileKey(); + ProfileKey profileKey4 = randomProfileKey(); + ProfileKey profileKey2b = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1, profileKey1), member(member2, profileKey2), member(member3, profileKey3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .modifiedProfileKeys(List.of(member(member1, profileKey1), member(member2, profileKey2b), member(member3, profileKey3), member(memberNotInGroup, profileKey4))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addModifiedProfileKeys(member(member2, profileKey2b)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .modifiedProfileKeys(List.of(member(member2, profileKey2b))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_7__add_pending_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addPendingMembers(pendingMember(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewPendingMembers(pendingMember(member1)) - .addNewPendingMembers(pendingMember(member2)) - .addNewPendingMembers(pendingMember(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .pendingMembers(List.of(pendingMember(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newPendingMembers(List.of(pendingMember(member1), pendingMember(member2), pendingMember(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addNewPendingMembers(pendingMember(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .newPendingMembers(List.of(pendingMember(member2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_8__delete_pending_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addPendingMembers(pendingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeletePendingMembers(pendingMemberRemoval(member1)) - .addDeletePendingMembers(pendingMemberRemoval(member2)) - .addDeletePendingMembers(pendingMemberRemoval(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .pendingMembers(List.of(pendingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deletePendingMembers(List.of(pendingMemberRemoval(member1), pendingMemberRemoval(member2), pendingMemberRemoval(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addDeletePendingMembers(pendingMemberRemoval(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .deletePendingMembers(List.of(pendingMemberRemoval(member2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_9__promote_pending_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - ProfileKey profileKey2 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addPendingMembers(pendingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addPromotePendingMembers(member(member1)) - .addPromotePendingMembers(member(member2, profileKey2)) - .addPromotePendingMembers(member(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + ProfileKey profileKey2 = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .pendingMembers(List.of(pendingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .promotePendingMembers(List.of(member(member1), member(member2, profileKey2), member(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addPromotePendingMembers(member(member2, profileKey2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .promotePendingMembers(List.of(member(member2, profileKey2))) + .build(); + assertEquals(expected, resolvedChanges); } @Test public void field_3_to_9__add_of_pending_member_converted_to_a_promote() { - UUID member1 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addPendingMembers(pendingMember(member1)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewMembers(member(member1)) - .build(); + UUID member1 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .pendingMembers(List.of(pendingMember(member1))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newMembers(List.of(member(member1))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addPromotePendingMembers(member(member1)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .promotePendingMembers(List.of(member(member1))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_10__title_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setTitle("Existing title") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTitle(DecryptedString.newBuilder().setValue("New title").build()) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .title("Existing title") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTitle(new DecryptedString.Builder().value_("New title").build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -295,12 +290,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_10__no_title_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setTitle("Existing title") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTitle(DecryptedString.newBuilder().setValue("Existing title").build()) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .title("Existing title") + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTitle(new DecryptedString.Builder().value_("Existing title").build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -309,12 +304,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_11__avatar_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAvatar("Existing avatar") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAvatar(DecryptedString.newBuilder().setValue("New avatar").build()) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .avatar("Existing avatar") + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAvatar(new DecryptedString.Builder().value_("New avatar").build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -323,12 +318,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_11__no_avatar_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAvatar("Existing avatar") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAvatar(DecryptedString.newBuilder().setValue("Existing avatar").build()) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .avatar("Existing avatar") + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAvatar(new DecryptedString.Builder().value_("Existing avatar").build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -337,12 +332,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_12__timer_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(123)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTimer(DecryptedTimer.newBuilder().setDuration(456)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .disappearingMessagesTimer(new DecryptedTimer.Builder().duration(123).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTimer(new DecryptedTimer.Builder().duration(456).build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -351,12 +346,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_12__no_timer_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDisappearingMessagesTimer(DecryptedTimer.newBuilder().setDuration(123)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewTimer(DecryptedTimer.newBuilder().setDuration(123)) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .disappearingMessagesTimer(new DecryptedTimer.Builder().duration(123).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newTimer(new DecryptedTimer.Builder().duration(123).build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -365,12 +360,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_13__attribute_access_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setAttributes(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAttributeAccess(AccessControl.AccessRequired.MEMBER) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().attributes(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAttributeAccess(AccessControl.AccessRequired.MEMBER) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -379,12 +374,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_13__no_attribute_access_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setAttributes(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().attributes(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newAttributeAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -393,12 +388,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_14__membership_access_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewMemberAccess(AccessControl.AccessRequired.MEMBER) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newMemberAccess(AccessControl.AccessRequired.MEMBER) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -407,12 +402,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_14__no_membership_access_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setMembers(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().members(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -421,12 +416,12 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_15__no_membership_access_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setAccessControl(AccessControl.newBuilder().setAddFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .accessControl(new AccessControl.Builder().addFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR).build()) + .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -435,115 +430,114 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_16__changes_to_add_requesting_members_when_full_members_are_removed() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - ProfileKey profileKey2 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addMembers(member(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(requestingMember(member1)) - .addNewRequestingMembers(requestingMember(member2, profileKey2)) - .addNewRequestingMembers(requestingMember(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + ProfileKey profileKey2 = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1), member(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(requestingMember(member1), requestingMember(member2, profileKey2), requestingMember(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(requestingMember(member2, profileKey2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(requestingMember(member2, profileKey2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_16__changes_to_add_requesting_members_when_pending_are_promoted() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - ProfileKey profileKey1 = randomProfileKey(); - ProfileKey profileKey2 = randomProfileKey(); - ProfileKey profileKey3 = randomProfileKey(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addPendingMembers(pendingMember(member1)) - .addPendingMembers(pendingMember(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewRequestingMembers(requestingMember(member1, profileKey1)) - .addNewRequestingMembers(requestingMember(member2, profileKey2)) - .addNewRequestingMembers(requestingMember(member3, profileKey3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + ProfileKey profileKey1 = randomProfileKey(); + ProfileKey profileKey2 = randomProfileKey(); + ProfileKey profileKey3 = randomProfileKey(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .pendingMembers(List.of(pendingMember(member1), pendingMember(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newRequestingMembers(List.of(requestingMember(member1, profileKey1), requestingMember(member2, profileKey2), requestingMember(member3, profileKey3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addPromotePendingMembers(member(member1, profileKey1)) - .addNewRequestingMembers(requestingMember(member2, profileKey2)) - .addPromotePendingMembers(member(member3, profileKey3)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .promotePendingMembers(List.of(member(member3, profileKey3), member(member1, profileKey1))) + .newRequestingMembers(List.of(requestingMember(member2, profileKey2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_17__changes_to_remove_missing_requesting_members_are_excluded() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addRequestingMembers(requestingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeleteRequestingMembers(UuidUtil.toByteString(member1)) - .addDeleteRequestingMembers(UuidUtil.toByteString(member2)) - .addDeleteRequestingMembers(UuidUtil.toByteString(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .requestingMembers(List.of(requestingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deleteRequestingMembers(List.of(UuidUtil.toByteString(member1), UuidUtil.toByteString(member2), UuidUtil.toByteString(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addDeleteRequestingMembers(UuidUtil.toByteString(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .deleteRequestingMembers(List.of(UuidUtil.toByteString(member2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_18__promote_requesting_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addRequestingMembers(requestingMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addPromoteRequestingMembers(approveMember(member1)) - .addPromoteRequestingMembers(approveMember(member2)) - .addPromoteRequestingMembers(approveMember(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .requestingMembers(List.of(requestingMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .promoteRequestingMembers(List.of(approveMember(member1), approveMember(member2), approveMember(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addPromoteRequestingMembers(approveMember(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .promoteRequestingMembers(List.of(approveMember(member2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_19__password_change_is_kept() { - ByteString password1 = ByteString.copyFrom(Util.getSecretBytes(16)); - ByteString password2 = ByteString.copyFrom(Util.getSecretBytes(16)); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setInviteLinkPassword(password1) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewInviteLinkPassword(password2) - .build(); + ByteString password1 = ByteString.of(Util.getSecretBytes(16)); + ByteString password2 = ByteString.of(Util.getSecretBytes(16)); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .inviteLinkPassword(password1) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newInviteLinkPassword(password2) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -552,12 +546,13 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_20__description_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDescription("Existing description") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewDescription(DecryptedString.newBuilder().setValue("New description").build()) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .description("Existing description") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newDescription(new DecryptedString.Builder().value_("New description").build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -566,12 +561,13 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_20__no_description_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setDescription("Existing description") - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewDescription(DecryptedString.newBuilder().setValue("Existing description").build()) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .description("Existing description") + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newDescription(new DecryptedString.Builder().value_("Existing description").build()) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -580,12 +576,13 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_21__announcement_change_is_preserved() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setIsAnnouncementGroup(EnabledState.DISABLED) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewIsAnnouncementGroup(EnabledState.ENABLED) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .isAnnouncementGroup(EnabledState.DISABLED) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newIsAnnouncementGroup(EnabledState.ENABLED) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -594,12 +591,13 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_21__no_announcement_change_is_removed() { - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .setIsAnnouncementGroup(EnabledState.ENABLED) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .setNewIsAnnouncementGroup(EnabledState.ENABLED) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .isAnnouncementGroup(EnabledState.ENABLED) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newIsAnnouncementGroup(EnabledState.ENABLED) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); @@ -608,49 +606,48 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { @Test public void field_22__add_banned_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addBannedMembers(bannedMember(member3)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addNewBannedMembers(bannedMember(member1)) - .addNewBannedMembers(bannedMember(member2)) - .addNewBannedMembers(bannedMember(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .bannedMembers(List.of(bannedMember(member3))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .newBannedMembers(List.of(bannedMember(member1), bannedMember(member2), bannedMember(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addNewBannedMembers(bannedMember(member1)) - .addNewBannedMembers(bannedMember(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .newBannedMembers(List.of(bannedMember(member1), bannedMember(member2))) + .build(); assertEquals(expected, resolvedChanges); } @Test public void field_23__delete_banned_members() { - UUID member1 = UUID.randomUUID(); - UUID member2 = UUID.randomUUID(); - UUID member3 = UUID.randomUUID(); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(member1)) - .addBannedMembers(bannedMember(member2)) - .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addDeleteBannedMembers(bannedMember(member1)) - .addDeleteBannedMembers(bannedMember(member2)) - .addDeleteBannedMembers(bannedMember(member3)) - .build(); + UUID member1 = UUID.randomUUID(); + UUID member2 = UUID.randomUUID(); + UUID member3 = UUID.randomUUID(); + + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(member1))) + .bannedMembers(List.of(bannedMember(member2))) + .build(); + + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .deleteBannedMembers(List.of(bannedMember(member1), bannedMember(member2), bannedMember(member3))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addDeleteBannedMembers(bannedMember(member2)) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .deleteBannedMembers(List.of(bannedMember(member2))) + .build(); assertEquals(expected, resolvedChanges); } @@ -660,20 +657,19 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test { DecryptedMember member1 = pendingPniAciMember(UUID.randomUUID(), UUID.randomUUID(), randomProfileKey()); DecryptedMember member2 = pendingPniAciMember(UUID.randomUUID(), UUID.randomUUID(), randomProfileKey()); - DecryptedGroup groupState = DecryptedGroup.newBuilder() - .addMembers(member(UuidUtil.fromByteString(member1.getAciBytes()))) - .build(); + DecryptedGroup groupState = new DecryptedGroup.Builder() + .members(List.of(member(UuidUtil.fromByteString(member1.aciBytes)))) + .build(); - DecryptedGroupChange decryptedChange = DecryptedGroupChange.newBuilder() - .addPromotePendingPniAciMembers(pendingPniAciMember(member1.getAciBytes(), member1.getPniBytes(), member1.getProfileKey())) - .addPromotePendingPniAciMembers(pendingPniAciMember(member2.getAciBytes(), member2.getPniBytes(), member2.getProfileKey())) - .build(); + DecryptedGroupChange decryptedChange = new DecryptedGroupChange.Builder() + .promotePendingPniAciMembers(List.of(pendingPniAciMember(member1.aciBytes, member1.pniBytes, member1.profileKey), pendingPniAciMember(member2.aciBytes, member2.pniBytes, member2.profileKey))) + .build(); DecryptedGroupChange resolvedChanges = GroupChangeUtil.resolveConflict(groupState, decryptedChange).build(); - DecryptedGroupChange expected = DecryptedGroupChange.newBuilder() - .addPromotePendingPniAciMembers(pendingPniAciMember(member2.getAciBytes(), member2.getPniBytes(), member2.getProfileKey())) - .build(); + DecryptedGroupChange expected = new DecryptedGroupChange.Builder() + .promotePendingPniAciMembers(List.of(pendingPniAciMember(member2.aciBytes, member2.pniBytes, member2.profileKey))) + .build(); assertEquals(expected, resolvedChanges); } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_ban_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_ban_Test.java index 38a4316ba6..df23698390 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_ban_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_ban_Test.java @@ -1,16 +1,11 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Before; import org.junit.Test; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.groups.GroupMasterKey; import org.signal.libsignal.zkgroup.groups.GroupSecretParams; -import org.signal.storageservice.protos.groups.BannedMember; import org.signal.storageservice.protos.groups.GroupChange; -import org.signal.storageservice.protos.groups.GroupChange.Actions.AddBannedMemberAction; -import org.signal.storageservice.protos.groups.GroupChange.Actions.DeleteBannedMemberAction; import org.signal.storageservice.protos.groups.local.DecryptedBannedMember; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; @@ -24,6 +19,8 @@ import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import okio.ByteString; + import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -52,8 +49,8 @@ public final class GroupsV2Operations_ban_Test { false, Collections.emptyList()); - assertThat(banUuidsChange.getAddBannedMembersCount(), is(1)); - assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptServiceId(ban))); + assertThat(banUuidsChange.addBannedMembers.size(), is(1)); + assertThat(banUuidsChange.addBannedMembers.get(0).added.userId, is(groupOperations.encryptServiceId(ban))); } @Test @@ -69,8 +66,8 @@ public final class GroupsV2Operations_ban_Test { false, alreadyBanned); - assertThat(banUuidsChange.getAddBannedMembersCount(), is(1)); - assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptServiceId(toBan))); + assertThat(banUuidsChange.addBannedMembers.size(), is(1)); + assertThat(banUuidsChange.addBannedMembers.get(0).added.userId, is(groupOperations.encryptServiceId(toBan))); } @Test @@ -80,7 +77,7 @@ public final class GroupsV2Operations_ban_Test { DecryptedBannedMember oldest = null; for (int i = 0; i < 10; i++) { - DecryptedBannedMember member = bannedMember(UUID.randomUUID()).toBuilder().setTimestamp(100 + i).build(); + DecryptedBannedMember member = bannedMember(UUID.randomUUID()).newBuilder().timestamp(100 + i).build(); if (oldest == null) { oldest = member; } @@ -93,12 +90,12 @@ public final class GroupsV2Operations_ban_Test { false, alreadyBanned); - assertThat(banUuidsChange.getDeleteBannedMembersCount(), is(1)); - assertThat(banUuidsChange.getDeleteBannedMembers(0).getDeletedUserId(), is(groupOperations.encryptServiceId(ServiceId.parseOrThrow(oldest.getServiceIdBytes())))); + assertThat(banUuidsChange.deleteBannedMembers.size(), is(1)); + assertThat(banUuidsChange.deleteBannedMembers.get(0).deletedUserId, is(groupOperations.encryptServiceId(ServiceId.parseOrThrow(oldest.serviceIdBytes)))); - assertThat(banUuidsChange.getAddBannedMembersCount(), is(1)); - assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptServiceId(toBan))); + assertThat(banUuidsChange.addBannedMembers.size(), is(1)); + assertThat(banUuidsChange.addBannedMembers.get(0).added.userId, is(groupOperations.encryptServiceId(toBan))); } @Test @@ -109,12 +106,12 @@ public final class GroupsV2Operations_ban_Test { List alreadyBanned = new ArrayList<>(10); for (int i = 0; i < 10; i++) { - alreadyBanned.add(bannedMember(UUID.randomUUID()).toBuilder().setTimestamp(100 + i).build()); + alreadyBanned.add(bannedMember(UUID.randomUUID()).newBuilder().timestamp(100 + i).build()); } List oldest = new ArrayList<>(2); - oldest.add(groupOperations.encryptServiceId(ServiceId.parseOrThrow(alreadyBanned.get(0).getServiceIdBytes()))); - oldest.add(groupOperations.encryptServiceId(ServiceId.parseOrThrow(alreadyBanned.get(1).getServiceIdBytes()))); + oldest.add(groupOperations.encryptServiceId(ServiceId.parseOrThrow(alreadyBanned.get(0).serviceIdBytes))); + oldest.add(groupOperations.encryptServiceId(ServiceId.parseOrThrow(alreadyBanned.get(1).serviceIdBytes))); Collections.shuffle(alreadyBanned); @@ -122,19 +119,19 @@ public final class GroupsV2Operations_ban_Test { false, alreadyBanned); - assertThat(banUuidsChange.getDeleteBannedMembersCount(), is(2)); - assertThat(banUuidsChange.getDeleteBannedMembersList() + assertThat(banUuidsChange.deleteBannedMembers.size(), is(2)); + assertThat(banUuidsChange.deleteBannedMembers .stream() - .map(DeleteBannedMemberAction::getDeletedUserId) + .map(a -> a.deletedUserId) .collect(Collectors.toList()), hasItems(oldest.get(0), oldest.get(1))); - assertThat(banUuidsChange.getAddBannedMembersCount(), is(2)); - assertThat(banUuidsChange.getAddBannedMembersList() + assertThat(banUuidsChange.addBannedMembers.size(), is(2)); + assertThat(banUuidsChange.addBannedMembers .stream() - .map(AddBannedMemberAction::getAdded) - .map(BannedMember::getUserId) + .map(a -> a.added) + .map(b -> b.userId) .collect(Collectors.toList()), hasItems(groupOperations.encryptServiceId(toBan.get(0)), groupOperations.encryptServiceId(toBan.get(1)))); diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_change_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_change_Test.java index 26952fe34b..1b963514f9 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_change_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_change_Test.java @@ -1,8 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.junit.Before; import org.junit.Test; import org.signal.libsignal.zkgroup.InvalidInputException; @@ -39,12 +36,16 @@ import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.util.Util; import org.whispersystems.signalservice.testutil.LibSignalLibraryUtil; +import java.io.IOException; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber; @@ -76,10 +77,10 @@ public final class GroupsV2Operations_decrypt_change_Test { } @Test - public void cannot_decrypt_change_with_epoch_higher_than_known() throws InvalidProtocolBufferException, VerificationFailedException, InvalidGroupStateException { - GroupChange change = GroupChange.newBuilder() - .setChangeEpoch(GroupsV2Operations.HIGHEST_KNOWN_EPOCH + 1) - .build(); + public void cannot_decrypt_change_with_epoch_higher_than_known() throws IOException, VerificationFailedException, InvalidGroupStateException { + GroupChange change = new GroupChange.Builder() + .changeEpoch(GroupsV2Operations.HIGHEST_KNOWN_EPOCH + 1) + .build(); Optional decryptedGroupChangeOptional = groupOperations.decryptChange(change, false); @@ -88,10 +89,10 @@ public final class GroupsV2Operations_decrypt_change_Test { @Test public void can_pass_revision_through_encrypt_and_decrypt_methods() { - assertDecryption(GroupChange.Actions.newBuilder() - .setRevision(1), - DecryptedGroupChange.newBuilder() - .setRevision(1)); + assertDecryption(new GroupChange.Actions.Builder() + .revision(1), + new DecryptedGroupChange.Builder() + .revision(1)); } @Test @@ -102,14 +103,15 @@ public final class GroupsV2Operations_decrypt_change_Test { GroupCandidate groupCandidate = groupCandidate(newMember, profileKey); assertDecryption(groupOperations.createModifyGroupMembershipChange(Collections.singleton(groupCandidate), Collections.emptySet(), self) - .setRevision(10), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .addNewMembers(DecryptedMember.newBuilder() - .setRole(Member.Role.DEFAULT) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setJoinedAtRevision(10) - .setAciBytes(newMember.toByteString()))); + .revision(10), + new DecryptedGroupChange.Builder() + .revision(10) + .newMembers(List.of(new DecryptedMember.Builder() + .role(Member.Role.DEFAULT) + .profileKey(ByteString.of(profileKey.serialize())) + .joinedAtRevision(10) + .aciBytes(newMember.toByteString()) + .build()))); } @Test @@ -119,14 +121,15 @@ public final class GroupsV2Operations_decrypt_change_Test { GroupCandidate groupCandidate = groupCandidate(newMember, profileKey); assertDecryption(groupOperations.createGroupJoinDirect(groupCandidate.getExpiringProfileKeyCredential().get()) - .setRevision(10), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .addNewMembers(DecryptedMember.newBuilder() - .setRole(Member.Role.DEFAULT) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setJoinedAtRevision(10) - .setAciBytes(newMember.toByteString()))); + .revision(10), + new DecryptedGroupChange.Builder() + .revision(10) + .newMembers(List.of(new DecryptedMember.Builder() + .role(Member.Role.DEFAULT) + .profileKey(ByteString.of(profileKey.serialize())) + .joinedAtRevision(10) + .aciBytes(newMember.toByteString()) + .build()))); } @Test @@ -137,26 +140,26 @@ public final class GroupsV2Operations_decrypt_change_Test { GroupCandidate groupCandidate = groupCandidate(newMember, profileKey); assertDecryption(groupOperations.createModifyGroupMembershipChange(Collections.singleton(groupCandidate), Collections.emptySet(), self) - .setRevision(10), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .addNewMembers(DecryptedMember.newBuilder() - .setRole(Member.Role.DEFAULT) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setJoinedAtRevision(10) - .setAciBytes(newMember.toByteString()))); + .revision(10), + new DecryptedGroupChange.Builder() + .revision(10) + .newMembers(List.of(new DecryptedMember.Builder() + .role(Member.Role.DEFAULT) + .profileKey(ByteString.of(profileKey.serialize())) + .joinedAtRevision(10) + .aciBytes(newMember.toByteString()) + .build()))); } @Test(expected = InvalidGroupStateException.class) - public void cannot_decrypt_member_additions_with_bad_cipher_text_field3() throws InvalidProtocolBufferException, VerificationFailedException, InvalidGroupStateException { + public void cannot_decrypt_member_additions_with_bad_cipher_text_field3() throws IOException, VerificationFailedException, InvalidGroupStateException { byte[] randomPresentation = Util.getSecretBytes(5); - GroupChange.Actions.Builder actions = GroupChange.Actions.newBuilder(); + GroupChange.Actions.Builder actions = new GroupChange.Actions.Builder(); - actions.addAddMembers(GroupChange.Actions.AddMemberAction.newBuilder() - .setAdded(Member.newBuilder().setRole(Member.Role.DEFAULT) - .setPresentation(ByteString.copyFrom(randomPresentation)))); + actions.addMembers(List.of(new GroupChange.Actions.AddMemberAction.Builder().added(new Member.Builder().role(Member.Role.DEFAULT) + .presentation(ByteString.of(randomPresentation)).build()).build())); - groupOperations.decryptChange(GroupChange.newBuilder().setActions(actions.build().toByteString()).build(), false); + groupOperations.decryptChange(new GroupChange.Builder().actions(actions.build().encodeByteString()).build(), false); } @Test @@ -164,21 +167,20 @@ public final class GroupsV2Operations_decrypt_change_Test { ACI oldMember = ACI.from(UUID.randomUUID()); assertDecryption(groupOperations.createRemoveMembersChange(Collections.singleton(oldMember), false, Collections.emptyList()) - .setRevision(10), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .addDeleteMembers(oldMember.toByteString())); + .revision(10), + new DecryptedGroupChange.Builder() + .revision(10) + .deleteMembers(List.of(oldMember.toByteString()))); } @Test(expected = InvalidGroupStateException.class) - public void cannot_decrypt_member_removals_with_bad_cipher_text_field4() throws InvalidProtocolBufferException, VerificationFailedException, InvalidGroupStateException { + public void cannot_decrypt_member_removals_with_bad_cipher_text_field4() throws IOException, VerificationFailedException, InvalidGroupStateException { byte[] randomPresentation = Util.getSecretBytes(5); - GroupChange.Actions.Builder actions = GroupChange.Actions.newBuilder(); + GroupChange.Actions.Builder actions = new GroupChange.Actions.Builder(); - actions.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder() - .setDeletedUserId(ByteString.copyFrom(randomPresentation))); + actions.deleteMembers(List.of(new GroupChange.Actions.DeleteMemberAction.Builder().deletedUserId(ByteString.of(randomPresentation)).build())); - groupOperations.decryptChange(GroupChange.newBuilder().setActions(actions.build().toByteString()).build(), false); + groupOperations.decryptChange(new GroupChange.Builder().actions(actions.build().encodeByteString()).build(), false); } @Test @@ -186,10 +188,11 @@ public final class GroupsV2Operations_decrypt_change_Test { ACI member = ACI.from(UUID.randomUUID()); assertDecryption(groupOperations.createChangeMemberRole(member, Member.Role.ADMINISTRATOR), - DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder() - .setAciBytes(member.toByteString()) - .setRole(Member.Role.ADMINISTRATOR))); + new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(new DecryptedModifyMemberRole.Builder() + .aciBytes(member.toByteString()) + .role(Member.Role.ADMINISTRATOR) + .build()))); } @Test @@ -197,10 +200,10 @@ public final class GroupsV2Operations_decrypt_change_Test { ACI member = ACI.from(UUID.randomUUID()); assertDecryption(groupOperations.createChangeMemberRole(member, Member.Role.DEFAULT), - DecryptedGroupChange.newBuilder() - .addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder() - .setAciBytes(member.toByteString()) - .setRole(Member.Role.DEFAULT))); + new DecryptedGroupChange.Builder() + .modifyMemberRoles(List.of(new DecryptedModifyMemberRole.Builder() + .aciBytes(member.toByteString()) + .role(Member.Role.DEFAULT).build()))); } @Test @@ -210,14 +213,15 @@ public final class GroupsV2Operations_decrypt_change_Test { GroupCandidate groupCandidate = groupCandidate(self, profileKey); assertDecryption(groupOperations.createUpdateProfileKeyCredentialChange(groupCandidate.getExpiringProfileKeyCredential().get()) - .setRevision(10), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .addModifiedProfileKeys(DecryptedMember.newBuilder() - .setRole(Member.Role.UNKNOWN) - .setJoinedAtRevision(-1) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setAciBytes(self.toByteString()))); + .revision(10), + new DecryptedGroupChange.Builder() + .revision(10) + .modifiedProfileKeys(List.of(new DecryptedMember.Builder() + .role(Member.Role.UNKNOWN) + .joinedAtRevision(-1) + .profileKey(ByteString.of(profileKey.serialize())) + .aciBytes(self.toByteString()) + .build()))); } @Test @@ -227,14 +231,15 @@ public final class GroupsV2Operations_decrypt_change_Test { GroupCandidate groupCandidate = new GroupCandidate(newMember, Optional.empty()); assertDecryption(groupOperations.createModifyGroupMembershipChange(Collections.singleton(groupCandidate), Collections.emptySet(), self) - .setRevision(13), - DecryptedGroupChange.newBuilder() - .setRevision(13) - .addNewPendingMembers(DecryptedPendingMember.newBuilder() - .setAddedByAci(self.toByteString()) - .setServiceIdCipherText(groupOperations.encryptServiceId(newMember)) - .setRole(Member.Role.DEFAULT) - .setServiceIdBytes(newMember.toByteString()))); + .revision(13), + new DecryptedGroupChange.Builder() + .revision(13) + .newPendingMembers(List.of(new DecryptedPendingMember.Builder() + .addedByAci(self.toByteString()) + .serviceIdCipherText(groupOperations.encryptServiceId(newMember)) + .role(Member.Role.DEFAULT) + .serviceIdBytes(newMember.toByteString()) + .build()))); } @Test @@ -243,24 +248,25 @@ public final class GroupsV2Operations_decrypt_change_Test { UuidCiphertext uuidCiphertext = new UuidCiphertext(groupOperations.encryptServiceId(oldMember).toByteArray()); assertDecryption(groupOperations.createRemoveInvitationChange(Collections.singleton(uuidCiphertext)), - DecryptedGroupChange.newBuilder() - .addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(oldMember.toByteString()) - .setServiceIdCipherText(ByteString.copyFrom(uuidCiphertext.serialize())))); + new DecryptedGroupChange.Builder() + .deletePendingMembers(List.of(new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(oldMember.toByteString()) + .serviceIdCipherText(ByteString.of(uuidCiphertext.serialize())) + .build()))); } @Test public void can_decrypt_pending_member_removals_with_bad_cipher_text_field8() { byte[] uuidCiphertext = Util.getSecretBytes(60); - assertDecryption(GroupChange.Actions - .newBuilder() - .addDeletePendingMembers(GroupChange.Actions.DeletePendingMemberAction.newBuilder() - .setDeletedUserId(ByteString.copyFrom(uuidCiphertext))), - DecryptedGroupChange.newBuilder() - .addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(UuidUtil.toByteString(UuidUtil.UNKNOWN_UUID)) - .setServiceIdCipherText(ByteString.copyFrom(uuidCiphertext)))); + assertDecryption(new GroupChange.Actions.Builder() + .deletePendingMembers(List.of(new GroupChange.Actions.DeletePendingMemberAction.Builder() + .deletedUserId(ByteString.of(uuidCiphertext)).build())), + new DecryptedGroupChange.Builder() + .deletePendingMembers(List.of(new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(UuidUtil.toByteString(UuidUtil.UNKNOWN_UUID)) + .serviceIdCipherText(ByteString.of(uuidCiphertext)) + .build()))); } @Test @@ -270,62 +276,63 @@ public final class GroupsV2Operations_decrypt_change_Test { GroupCandidate groupCandidate = groupCandidate(newMember, profileKey); assertDecryption(groupOperations.createAcceptInviteChange(groupCandidate.getExpiringProfileKeyCredential().get()), - DecryptedGroupChange.newBuilder() - .addPromotePendingMembers(DecryptedMember.newBuilder() - .setAciBytes(newMember.toByteString()) - .setRole(Member.Role.DEFAULT) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setJoinedAtRevision(-1))); + new DecryptedGroupChange.Builder() + .promotePendingMembers(List.of(new DecryptedMember.Builder() + .aciBytes(newMember.toByteString()) + .role(Member.Role.DEFAULT) + .profileKey(ByteString.of(profileKey.serialize())) + .joinedAtRevision(-1) + .build()))); } @Test public void can_decrypt_title_field_10() { assertDecryption(groupOperations.createModifyGroupTitle("New title"), - DecryptedGroupChange.newBuilder() - .setNewTitle(DecryptedString.newBuilder().setValue("New title"))); + new DecryptedGroupChange.Builder() + .newTitle(new DecryptedString.Builder().value_("New title").build())); } @Test public void can_decrypt_avatar_key_field_11() { - assertDecryption(GroupChange.Actions.newBuilder() - .setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder().setAvatar("New avatar")), - DecryptedGroupChange.newBuilder() - .setNewAvatar(DecryptedString.newBuilder().setValue("New avatar"))); + assertDecryption(new GroupChange.Actions.Builder() + .modifyAvatar(new GroupChange.Actions.ModifyAvatarAction.Builder().avatar("New avatar").build()), + new DecryptedGroupChange.Builder() + .newAvatar(new DecryptedString.Builder().value_("New avatar").build())); } @Test public void can_decrypt_timer_value_field_12() { assertDecryption(groupOperations.createModifyGroupTimerChange(100), - DecryptedGroupChange.newBuilder() - .setNewTimer(DecryptedTimer.newBuilder().setDuration(100))); + new DecryptedGroupChange.Builder() + .newTimer(new DecryptedTimer.Builder().duration(100).build())); } @Test public void can_pass_through_new_attribute_access_rights_field_13() { assertDecryption(groupOperations.createChangeAttributesRights(AccessControl.AccessRequired.MEMBER), - DecryptedGroupChange.newBuilder() - .setNewAttributeAccess(AccessControl.AccessRequired.MEMBER)); + new DecryptedGroupChange.Builder() + .newAttributeAccess(AccessControl.AccessRequired.MEMBER)); } @Test public void can_pass_through_new_membership_rights_field_14() { assertDecryption(groupOperations.createChangeMembershipRights(AccessControl.AccessRequired.ADMINISTRATOR), - DecryptedGroupChange.newBuilder() - .setNewMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR)); + new DecryptedGroupChange.Builder() + .newMemberAccess(AccessControl.AccessRequired.ADMINISTRATOR)); } @Test public void can_pass_through_new_add_by_invite_link_rights_field_15() { assertDecryption(groupOperations.createChangeJoinByLinkRights(AccessControl.AccessRequired.ADMINISTRATOR), - DecryptedGroupChange.newBuilder() - .setNewInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR)); + new DecryptedGroupChange.Builder() + .newInviteLinkAccess(AccessControl.AccessRequired.ADMINISTRATOR)); } @Test public void can_pass_through_new_add_by_invite_link_rights_field_15_unsatisfiable() { assertDecryption(groupOperations.createChangeJoinByLinkRights(AccessControl.AccessRequired.UNSATISFIABLE), - DecryptedGroupChange.newBuilder() - .setNewInviteLinkAccess(AccessControl.AccessRequired.UNSATISFIABLE)); + new DecryptedGroupChange.Builder() + .newInviteLinkAccess(AccessControl.AccessRequired.UNSATISFIABLE)); } @Test @@ -335,12 +342,13 @@ public final class GroupsV2Operations_decrypt_change_Test { GroupCandidate groupCandidate = groupCandidate(newRequestingMember, profileKey); assertDecryption(groupOperations.createGroupJoinRequest(groupCandidate.getExpiringProfileKeyCredential().get()) - .setRevision(10), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .addNewRequestingMembers(DecryptedRequestingMember.newBuilder() - .setAciBytes(newRequestingMember.toByteString()) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())))); + .revision(10), + new DecryptedGroupChange.Builder() + .revision(10) + .newRequestingMembers(List.of(new DecryptedRequestingMember.Builder() + .aciBytes(newRequestingMember.toByteString()) + .profileKey(ByteString.of(profileKey.serialize())) + .build()))); } @Test @@ -348,11 +356,11 @@ public final class GroupsV2Operations_decrypt_change_Test { ACI newRequestingMember = ACI.from(UUID.randomUUID()); assertDecryption(groupOperations.createRefuseGroupJoinRequest(Collections.singleton(newRequestingMember), true, Collections.emptyList()) - .setRevision(10), - DecryptedGroupChange.newBuilder() - .setRevision(10) - .addDeleteRequestingMembers(newRequestingMember.toByteString()) - .addNewBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBytes(newRequestingMember.toByteString()).build())); + .revision(10), + new DecryptedGroupChange.Builder() + .revision(10) + .deleteRequestingMembers(List.of(newRequestingMember.toByteString())) + .newBannedMembers(List.of(new DecryptedBannedMember.Builder().serviceIdBytes(newRequestingMember.toByteString()).build()))); } @Test @@ -360,39 +368,42 @@ public final class GroupsV2Operations_decrypt_change_Test { UUID newRequestingMember = UUID.randomUUID(); assertDecryption(groupOperations.createApproveGroupJoinRequest(Collections.singleton(newRequestingMember)) - .setRevision(15), - DecryptedGroupChange.newBuilder() - .setRevision(15) - .addPromoteRequestingMembers(DecryptedApproveMember.newBuilder() - .setRole(Member.Role.DEFAULT) - .setAciBytes(UuidUtil.toByteString(newRequestingMember)))); + .revision(15), + new DecryptedGroupChange.Builder() + .revision(15) + .promoteRequestingMembers(List.of(new DecryptedApproveMember.Builder() + .role(Member.Role.DEFAULT) + .aciBytes(UuidUtil.toByteString(newRequestingMember)) + .build()))); } @Test public void can_pass_through_new_invite_link_password_field19() { byte[] newPassword = Util.getSecretBytes(16); - assertDecryption(GroupChange.Actions.newBuilder() - .setModifyInviteLinkPassword(GroupChange.Actions.ModifyInviteLinkPasswordAction.newBuilder() - .setInviteLinkPassword(ByteString.copyFrom(newPassword))), - DecryptedGroupChange.newBuilder() - .setNewInviteLinkPassword(ByteString.copyFrom(newPassword))); + assertDecryption(new GroupChange.Actions.Builder() + .modifyInviteLinkPassword(new GroupChange.Actions.ModifyInviteLinkPasswordAction.Builder() + .inviteLinkPassword(ByteString.of(newPassword)) + .build()), + new DecryptedGroupChange.Builder() + .newInviteLinkPassword(ByteString.of(newPassword))); } @Test public void can_pass_through_new_description_field20() { assertDecryption(groupOperations.createModifyGroupDescription("New Description"), - DecryptedGroupChange.newBuilder() - .setNewDescription(DecryptedString.newBuilder().setValue("New Description").build())); + new DecryptedGroupChange.Builder() + .newDescription(new DecryptedString.Builder().value_("New Description").build())); } @Test public void can_pass_through_new_announcment_only_field21() { - assertDecryption(GroupChange.Actions.newBuilder() - .setModifyAnnouncementsOnly(GroupChange.Actions.ModifyAnnouncementsOnlyAction.newBuilder() - .setAnnouncementsOnly(true)), - DecryptedGroupChange.newBuilder() - .setNewIsAnnouncementGroup(EnabledState.ENABLED)); + assertDecryption(new GroupChange.Actions.Builder() + .modifyAnnouncementsOnly(new GroupChange.Actions.ModifyAnnouncementsOnlyAction.Builder() + .announcementsOnly(true) + .build()), + new DecryptedGroupChange.Builder() + .newIsAnnouncementGroup(EnabledState.ENABLED)); } @Test @@ -400,11 +411,12 @@ public final class GroupsV2Operations_decrypt_change_Test { ACI ban = ACI.from(UUID.randomUUID()); assertDecryption(groupOperations.createBanServiceIdsChange(Collections.singleton(ban), false, Collections.emptyList()) - .setRevision(13), - DecryptedGroupChange.newBuilder() - .setRevision(13) - .addNewBannedMembers(DecryptedBannedMember.newBuilder() - .setServiceIdBytes(ban.toByteString()))); + .revision(13), + new DecryptedGroupChange.Builder() + .revision(13) + .newBannedMembers(List.of(new DecryptedBannedMember.Builder() + .serviceIdBytes(ban.toByteString()) + .build()))); } @Test @@ -412,11 +424,11 @@ public final class GroupsV2Operations_decrypt_change_Test { ACI ban = ACI.from(UUID.randomUUID()); assertDecryption(groupOperations.createUnbanServiceIdsChange(Collections.singleton(ban)) - .setRevision(13), - DecryptedGroupChange.newBuilder() - .setRevision(13) - .addDeleteBannedMembers(DecryptedBannedMember.newBuilder() - .setServiceIdBytes(ban.toByteString()))); + .revision(13), + new DecryptedGroupChange.Builder() + .revision(13) + .deleteBannedMembers(List.of(new DecryptedBannedMember.Builder() + .serviceIdBytes(ban.toByteString()).build()))); } @Test @@ -425,24 +437,26 @@ public final class GroupsV2Operations_decrypt_change_Test { PNI memberPni = PNI.from(UUID.randomUUID()); ProfileKey profileKey = newProfileKey(); - GroupChange.Actions.Builder builder = GroupChange.Actions.newBuilder() - .setSourceServiceId(groupOperations.encryptServiceId(memberPni)) - .setRevision(5) - .addPromotePendingPniAciMembers(GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.newBuilder() - .setUserId(groupOperations.encryptServiceId(memberAci)) - .setPni(groupOperations.encryptServiceId(memberPni)) - .setProfileKey(encryptProfileKey(memberAci, profileKey))); + GroupChange.Actions.Builder builder = new GroupChange.Actions.Builder() + .sourceServiceId(groupOperations.encryptServiceId(memberPni)) + .revision(5) + .promotePendingPniAciMembers(List.of(new GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.Builder() + .userId(groupOperations.encryptServiceId(memberAci)) + .pni(groupOperations.encryptServiceId(memberPni)) + .profileKey(encryptProfileKey(memberAci, profileKey)) + .build())); assertDecryptionWithEditorSet(builder, - DecryptedGroupChange.newBuilder() - .setEditorServiceIdBytes(memberAci.toByteString()) - .setRevision(5) - .addPromotePendingPniAciMembers(DecryptedMember.newBuilder() - .setAciBytes(memberAci.toByteString()) - .setPniBytes(memberPni.toByteString()) - .setRole(Member.Role.DEFAULT) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .setJoinedAtRevision(5))); + new DecryptedGroupChange.Builder() + .editorServiceIdBytes(memberAci.toByteString()) + .revision(5) + .promotePendingPniAciMembers(List.of(new DecryptedMember.Builder() + .aciBytes(memberAci.toByteString()) + .pniBytes(memberPni.toByteString()) + .role(Member.Role.DEFAULT) + .profileKey(ByteString.of(profileKey.serialize())) + .joinedAtRevision(5) + .build()))); } private static ProfileKey newProfileKey() { @@ -454,7 +468,7 @@ public final class GroupsV2Operations_decrypt_change_Test { } private ByteString encryptProfileKey(ACI aci, ProfileKey profileKey) { - return ByteString.copyFrom(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, aci.getLibSignalAci()).serialize()); + return ByteString.of(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, aci.getLibSignalAci()).serialize()); } static GroupCandidate groupCandidate(UUID uuid) { @@ -484,7 +498,7 @@ public final class GroupsV2Operations_decrypt_change_Test { DecryptedGroupChange.Builder expectedDecrypted) { ACI editor = ACI.from(UUID.randomUUID()); - assertDecryptionWithEditorSet(inputChange.setSourceServiceId(groupOperations.encryptServiceId(editor)), expectedDecrypted.setEditorServiceIdBytes(editor.toByteString())); + assertDecryptionWithEditorSet(inputChange.sourceServiceId(groupOperations.encryptServiceId(editor)), expectedDecrypted.editorServiceIdBytes(editor.toByteString())); } void assertDecryptionWithEditorSet(GroupChange.Actions.Builder inputChange, @@ -492,9 +506,9 @@ public final class GroupsV2Operations_decrypt_change_Test { { GroupChange.Actions actions = inputChange.build(); - GroupChange change = GroupChange.newBuilder() - .setActions(actions.toByteString()) - .build(); + GroupChange change = new GroupChange.Builder() + .actions(actions.encodeByteString()) + .build(); DecryptedGroupChange decryptedGroupChange = decrypt(change); @@ -505,7 +519,7 @@ public final class GroupsV2Operations_decrypt_change_Test { private DecryptedGroupChange decrypt(GroupChange build) { try { return groupOperations.decryptChange(build, false).get(); - } catch (InvalidProtocolBufferException | VerificationFailedException | InvalidGroupStateException e) { + } catch (IOException | VerificationFailedException | InvalidGroupStateException e) { throw new AssertionError(e); } } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_groupJoinInfo_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_groupJoinInfo_Test.java index e4b46ebbed..c2ac306dac 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_groupJoinInfo_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_groupJoinInfo_Test.java @@ -46,100 +46,100 @@ public final class GroupsV2Operations_decrypt_groupJoinInfo_Test { @Test public void decrypt_title_field_2() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setTitle(groupOperations.encryptTitle("Title!")) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .title(groupOperations.encryptTitle("Title!")) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertEquals("Title!", decryptedGroupJoinInfo.getTitle()); + assertEquals("Title!", decryptedGroupJoinInfo.title); } @Test public void avatar_field_passed_through_3() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setAvatar("AvatarCdnKey") + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .avatar("AvatarCdnKey") .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertEquals("AvatarCdnKey", decryptedGroupJoinInfo.getAvatar()); + assertEquals("AvatarCdnKey", decryptedGroupJoinInfo.avatar); } @Test public void member_count_passed_through_4() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setMemberCount(97) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .memberCount(97) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertEquals(97, decryptedGroupJoinInfo.getMemberCount()); + assertEquals(97, decryptedGroupJoinInfo.memberCount); } @Test public void add_from_invite_link_access_control_passed_though_5_administrator() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setAddFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .addFromInviteLink(AccessControl.AccessRequired.ADMINISTRATOR) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertEquals(AccessControl.AccessRequired.ADMINISTRATOR, decryptedGroupJoinInfo.getAddFromInviteLink()); + assertEquals(AccessControl.AccessRequired.ADMINISTRATOR, decryptedGroupJoinInfo.addFromInviteLink); } @Test public void add_from_invite_link_access_control_passed_though_5_any() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setAddFromInviteLink(AccessControl.AccessRequired.ANY) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .addFromInviteLink(AccessControl.AccessRequired.ANY) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertEquals(AccessControl.AccessRequired.ANY, decryptedGroupJoinInfo.getAddFromInviteLink()); + assertEquals(AccessControl.AccessRequired.ANY, decryptedGroupJoinInfo.addFromInviteLink); } @Test public void revision_passed_though_6() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setRevision(11) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .revision(11) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertEquals(11, decryptedGroupJoinInfo.getRevision()); + assertEquals(11, decryptedGroupJoinInfo.revision); } @Test public void pending_approval_passed_though_7_true() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setPendingAdminApproval(true) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .pendingAdminApproval(true) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertTrue(decryptedGroupJoinInfo.getPendingAdminApproval()); + assertTrue(decryptedGroupJoinInfo.pendingAdminApproval); } @Test public void pending_approval_passed_though_7_false() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setPendingAdminApproval(false) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .pendingAdminApproval(false) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertFalse(decryptedGroupJoinInfo.getPendingAdminApproval()); + assertFalse(decryptedGroupJoinInfo.pendingAdminApproval); } @Test public void decrypt_description_field_8() { - GroupJoinInfo groupJoinInfo = GroupJoinInfo.newBuilder() - .setDescription(groupOperations.encryptDescription("Description!")) + GroupJoinInfo groupJoinInfo = new GroupJoinInfo.Builder() + .description(groupOperations.encryptDescription("Description!")) .build(); DecryptedGroupJoinInfo decryptedGroupJoinInfo = groupOperations.decryptGroupJoinInfo(groupJoinInfo); - assertEquals("Description!", decryptedGroupJoinInfo.getDescription()); + assertEquals("Description!", decryptedGroupJoinInfo.description); } } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_group_Test.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_group_Test.java index 5ffc002263..02bdef57e6 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_group_Test.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations_decrypt_group_Test.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.junit.Before; import org.junit.Test; import org.signal.libsignal.zkgroup.InvalidInputException; @@ -26,8 +24,11 @@ import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.internal.util.Util; import org.whispersystems.signalservice.testutil.LibSignalLibraryUtil; +import java.util.List; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertEquals; import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber; @@ -47,7 +48,7 @@ public final class GroupsV2Operations_decrypt_group_Test { groupOperations = new GroupsV2Operations(clientZkOperations, 1000).forGroup(groupSecretParams); } - /** + /** * Reflects over the generated protobuf class and ensures that no new fields have been added since we wrote this. *

* If we didn't, newly added fields would not be decrypted by {@link GroupsV2Operations.GroupOperations#decryptGroup}. @@ -59,65 +60,65 @@ public final class GroupsV2Operations_decrypt_group_Test { assertEquals("GroupOperations and its tests need updating to account for new fields on " + Group.class.getName(), 13, maxFieldFound); } - + @Test public void decrypt_title_field_2() throws VerificationFailedException, InvalidGroupStateException { - Group group = Group.newBuilder() - .setTitle(groupOperations.encryptTitle("Title!")) - .build(); + Group group = new Group.Builder() + .title(groupOperations.encryptTitle("Title!")) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals("Title!", decryptedGroup.getTitle()); + assertEquals("Title!", decryptedGroup.title); } @Test public void avatar_field_passed_through_3() throws VerificationFailedException, InvalidGroupStateException { - Group group = Group.newBuilder() - .setAvatar("AvatarCdnKey") - .build(); + Group group = new Group.Builder() + .avatar("AvatarCdnKey") + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals("AvatarCdnKey", decryptedGroup.getAvatar()); + assertEquals("AvatarCdnKey", decryptedGroup.avatar); } @Test public void decrypt_message_timer_field_4() throws VerificationFailedException, InvalidGroupStateException { - Group group = Group.newBuilder() - .setDisappearingMessagesTimer(groupOperations.encryptTimer(123)) - .build(); + Group group = new Group.Builder() + .disappearingMessagesTimer(groupOperations.encryptTimer(123)) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(123, decryptedGroup.getDisappearingMessagesTimer().getDuration()); + assertEquals(123, decryptedGroup.disappearingMessagesTimer.duration); } @Test public void pass_through_access_control_field_5() throws VerificationFailedException, InvalidGroupStateException { - AccessControl accessControl = AccessControl.newBuilder() - .setMembers(AccessControl.AccessRequired.ADMINISTRATOR) - .setAttributes(AccessControl.AccessRequired.MEMBER) - .setAddFromInviteLink(AccessControl.AccessRequired.UNSATISFIABLE) - .build(); - Group group = Group.newBuilder() - .setAccessControl(accessControl) - .build(); + AccessControl accessControl = new AccessControl.Builder() + .members(AccessControl.AccessRequired.ADMINISTRATOR) + .attributes(AccessControl.AccessRequired.MEMBER) + .addFromInviteLink(AccessControl.AccessRequired.UNSATISFIABLE) + .build(); + Group group = new Group.Builder() + .accessControl(accessControl) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(accessControl, decryptedGroup.getAccessControl()); + assertEquals(accessControl, decryptedGroup.accessControl); } @Test public void set_revision_field_6() throws VerificationFailedException, InvalidGroupStateException { - Group group = Group.newBuilder() - .setRevision(99) - .build(); + Group group = new Group.Builder() + .revision(99) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(99, decryptedGroup.getRevision()); + assertEquals(99, decryptedGroup.revision); } @Test @@ -127,34 +128,38 @@ public final class GroupsV2Operations_decrypt_group_Test { ProfileKey adminProfileKey = newProfileKey(); ProfileKey memberProfileKey = newProfileKey(); - Group group = Group.newBuilder() - .addMembers(Member.newBuilder() - .setRole(Member.Role.ADMINISTRATOR) - .setUserId(groupOperations.encryptServiceId(admin1)) - .setJoinedAtRevision(4) - .setProfileKey(encryptProfileKey(admin1, adminProfileKey))) - .addMembers(Member.newBuilder() - .setRole(Member.Role.DEFAULT) - .setUserId(groupOperations.encryptServiceId(member1)) - .setJoinedAtRevision(7) - .setProfileKey(encryptProfileKey(member1, memberProfileKey))) - .build(); + Group group = new Group.Builder() + .members(List.of(new Member.Builder() + .role(Member.Role.ADMINISTRATOR) + .userId(groupOperations.encryptServiceId(admin1)) + .joinedAtRevision(4) + .profileKey(encryptProfileKey(admin1, adminProfileKey)) + .build(), + new Member.Builder() + .role(Member.Role.DEFAULT) + .userId(groupOperations.encryptServiceId(member1)) + .joinedAtRevision(7) + .profileKey(encryptProfileKey(member1, memberProfileKey)) + .build())) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(DecryptedGroup.newBuilder() - .addMembers(DecryptedMember.newBuilder() - .setJoinedAtRevision(4) - .setAciBytes(admin1.toByteString()) - .setRole(Member.Role.ADMINISTRATOR) - .setProfileKey(ByteString.copyFrom(adminProfileKey.serialize()))) - .addMembers(DecryptedMember.newBuilder() - .setJoinedAtRevision(7) - .setRole(Member.Role.DEFAULT) - .setAciBytes(member1.toByteString()) - .setProfileKey(ByteString.copyFrom(memberProfileKey.serialize()))) - .build().getMembersList(), - decryptedGroup.getMembersList()); + assertEquals(new DecryptedGroup.Builder() + .members(List.of(new DecryptedMember.Builder() + .joinedAtRevision(4) + .aciBytes(admin1.toByteString()) + .role(Member.Role.ADMINISTRATOR) + .profileKey(ByteString.of(adminProfileKey.serialize())) + .build(), + new DecryptedMember.Builder() + .joinedAtRevision(7) + .role(Member.Role.DEFAULT) + .aciBytes(member1.toByteString()) + .profileKey(ByteString.of(memberProfileKey.serialize())) + .build())) + .build().members, + decryptedGroup.members); } @Test @@ -165,49 +170,58 @@ public final class GroupsV2Operations_decrypt_group_Test { ACI inviter1 = ACI.from(UUID.randomUUID()); ACI inviter2 = ACI.from(UUID.randomUUID()); - Group group = Group.newBuilder() - .addPendingMembers(PendingMember.newBuilder() - .setAddedByUserId(groupOperations.encryptServiceId(inviter1)) - .setTimestamp(100) - .setMember(Member.newBuilder() - .setRole(Member.Role.ADMINISTRATOR) - .setUserId(groupOperations.encryptServiceId(admin1)))) - .addPendingMembers(PendingMember.newBuilder() - .setAddedByUserId(groupOperations.encryptServiceId(inviter1)) - .setTimestamp(200) - .setMember(Member.newBuilder() - .setRole(Member.Role.DEFAULT) - .setUserId(groupOperations.encryptServiceId(member1)))) - .addPendingMembers(PendingMember.newBuilder() - .setAddedByUserId(groupOperations.encryptServiceId(inviter2)) - .setTimestamp(1500) - .setMember(Member.newBuilder() - .setUserId(groupOperations.encryptServiceId(member2)))) - .build(); + Group group = new Group.Builder() + .pendingMembers(List.of(new PendingMember.Builder() + .addedByUserId(groupOperations.encryptServiceId(inviter1)) + .timestamp(100) + .member(new Member.Builder() + .role(Member.Role.ADMINISTRATOR) + .userId(groupOperations.encryptServiceId(admin1)) + .build()) + .build(), + new PendingMember.Builder() + .addedByUserId(groupOperations.encryptServiceId(inviter1)) + .timestamp(200) + .member(new Member.Builder() + .role(Member.Role.DEFAULT) + .userId(groupOperations.encryptServiceId(member1)) + .build()) + .build(), + new PendingMember.Builder() + .addedByUserId(groupOperations.encryptServiceId(inviter2)) + .timestamp(1500) + .member(new Member.Builder() + .userId(groupOperations.encryptServiceId(member2)).build()) + .build())) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(DecryptedGroup.newBuilder() - .addPendingMembers(DecryptedPendingMember.newBuilder() - .setServiceIdBytes(admin1.toByteString()) - .setServiceIdCipherText(groupOperations.encryptServiceId(admin1)) - .setTimestamp(100) - .setAddedByAci(inviter1.toByteString()) - .setRole(Member.Role.ADMINISTRATOR)) - .addPendingMembers(DecryptedPendingMember.newBuilder() - .setServiceIdBytes(member1.toByteString()) - .setServiceIdCipherText(groupOperations.encryptServiceId(member1)) - .setTimestamp(200) - .setAddedByAci(inviter1.toByteString()) - .setRole(Member.Role.DEFAULT)) - .addPendingMembers(DecryptedPendingMember.newBuilder() - .setServiceIdBytes(member2.toByteString()) - .setServiceIdCipherText(groupOperations.encryptServiceId(member2)) - .setTimestamp(1500) - .setAddedByAci(inviter2.toByteString()) - .setRole(Member.Role.DEFAULT)) - .build().getPendingMembersList(), - decryptedGroup.getPendingMembersList()); + assertEquals(new DecryptedGroup.Builder() + .pendingMembers(List.of(new DecryptedPendingMember.Builder() + .serviceIdBytes(admin1.toByteString()) + .serviceIdCipherText(groupOperations.encryptServiceId(admin1)) + .timestamp(100) + .addedByAci(inviter1.toByteString()) + .role(Member.Role.ADMINISTRATOR) + .build(), + new DecryptedPendingMember.Builder() + .serviceIdBytes(member1.toByteString()) + .serviceIdCipherText(groupOperations.encryptServiceId(member1)) + .timestamp(200) + .addedByAci(inviter1.toByteString()) + .role(Member.Role.DEFAULT) + .build(), + new DecryptedPendingMember.Builder() + .serviceIdBytes(member2.toByteString()) + .serviceIdCipherText(groupOperations.encryptServiceId(member2)) + .timestamp(1500) + .addedByAci(inviter2.toByteString()) + .role(Member.Role.DEFAULT) + .build())) + .build() + .pendingMembers, + decryptedGroup.pendingMembers); } @Test @@ -217,82 +231,87 @@ public final class GroupsV2Operations_decrypt_group_Test { ProfileKey adminProfileKey = newProfileKey(); ProfileKey memberProfileKey = newProfileKey(); - Group group = Group.newBuilder() - .addRequestingMembers(RequestingMember.newBuilder() - .setUserId(groupOperations.encryptServiceId(admin1)) - .setProfileKey(encryptProfileKey(admin1, adminProfileKey)) - .setTimestamp(5000)) - .addRequestingMembers(RequestingMember.newBuilder() - .setUserId(groupOperations.encryptServiceId(member1)) - .setProfileKey(encryptProfileKey(member1, memberProfileKey)) - .setTimestamp(15000)) - .build(); + Group group = new Group.Builder() + .requestingMembers(List.of(new RequestingMember.Builder() + .userId(groupOperations.encryptServiceId(admin1)) + .profileKey(encryptProfileKey(admin1, adminProfileKey)) + .timestamp(5000) + .build(), + new RequestingMember.Builder() + .userId(groupOperations.encryptServiceId(member1)) + .profileKey(encryptProfileKey(member1, memberProfileKey)) + .timestamp(15000) + .build())) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(DecryptedGroup.newBuilder() - .addRequestingMembers(DecryptedRequestingMember.newBuilder() - .setAciBytes(admin1.toByteString()) - .setProfileKey(ByteString.copyFrom(adminProfileKey.serialize())) - .setTimestamp(5000)) - .addRequestingMembers(DecryptedRequestingMember.newBuilder() - .setAciBytes(member1.toByteString()) - .setProfileKey(ByteString.copyFrom(memberProfileKey.serialize())) - .setTimestamp(15000)) - .build().getRequestingMembersList(), - decryptedGroup.getRequestingMembersList()); + assertEquals(new DecryptedGroup.Builder() + .requestingMembers(List.of(new DecryptedRequestingMember.Builder() + .aciBytes(admin1.toByteString()) + .profileKey(ByteString.of(adminProfileKey.serialize())) + .timestamp(5000) + .build(), + new DecryptedRequestingMember.Builder() + .aciBytes(member1.toByteString()) + .profileKey(ByteString.of(memberProfileKey.serialize())) + .timestamp(15000) + .build())) + .build() + .requestingMembers, + decryptedGroup.requestingMembers); } @Test public void pass_through_group_link_password_field_10() throws VerificationFailedException, InvalidGroupStateException { - ByteString password = ByteString.copyFrom(Util.getSecretBytes(16)); - Group group = Group.newBuilder() - .setInviteLinkPassword(password) - .build(); + ByteString password = ByteString.of(Util.getSecretBytes(16)); + Group group = new Group.Builder() + .inviteLinkPassword(password) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(password, decryptedGroup.getInviteLinkPassword()); + assertEquals(password, decryptedGroup.inviteLinkPassword); } @Test public void decrypt_description_field_11() throws VerificationFailedException, InvalidGroupStateException { - Group group = Group.newBuilder() - .setDescription(groupOperations.encryptDescription("Description!")) - .build(); + Group group = new Group.Builder() + .description(groupOperations.encryptDescription("Description!")) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals("Description!", decryptedGroup.getDescription()); + assertEquals("Description!", decryptedGroup.description); } @Test public void decrypt_announcements_field_12() throws VerificationFailedException, InvalidGroupStateException { - Group group = Group.newBuilder() - .setAnnouncementsOnly(true) - .build(); + Group group = new Group.Builder() + .announcementsOnly(true) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(EnabledState.ENABLED, decryptedGroup.getIsAnnouncementGroup()); + assertEquals(EnabledState.ENABLED, decryptedGroup.isAnnouncementGroup); } @Test public void decrypt_banned_members_field_13() throws VerificationFailedException, InvalidGroupStateException { ACI member1 = ACI.from(UUID.randomUUID()); - Group group = Group.newBuilder() - .addBannedMembers(BannedMember.newBuilder().setUserId(groupOperations.encryptServiceId(member1))) - .build(); + Group group = new Group.Builder() + .bannedMembers(List.of(new BannedMember.Builder().userId(groupOperations.encryptServiceId(member1)).build())) + .build(); DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group); - assertEquals(1, decryptedGroup.getBannedMembersCount()); - assertEquals(DecryptedBannedMember.newBuilder().setServiceIdBytes(member1.toByteString()).build(), decryptedGroup.getBannedMembers(0)); + assertEquals(1, decryptedGroup.bannedMembers.size()); + assertEquals(new DecryptedBannedMember.Builder().serviceIdBytes(member1.toByteString()).build(), decryptedGroup.bannedMembers.get(0)); } private ByteString encryptProfileKey(ACI aci, ProfileKey profileKey) { - return ByteString.copyFrom(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, aci.getLibSignalAci()).serialize()); + return ByteString.of(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, aci.getLibSignalAci()).serialize()); } private static ProfileKey newProfileKey() { diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtoTestUtils.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtoTestUtils.java index cf07ca8c88..f404eb174a 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtoTestUtils.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtoTestUtils.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.ByteString; - import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.storageservice.protos.groups.Member; @@ -20,6 +18,9 @@ import java.security.SecureRandom; import java.util.Arrays; import java.util.UUID; +import okio.Buffer; +import okio.ByteString; + final class ProtoTestUtils { static ProfileKey randomProfileKey() { @@ -37,7 +38,7 @@ final class ProtoTestUtils { */ static ByteString encrypt(UUID uuid) { byte[] uuidBytes = UuidUtil.toByteArray(uuid); - return ByteString.copyFrom(Arrays.copyOf(uuidBytes, uuidBytes.length + 1)); + return ByteString.of(Arrays.copyOf(uuidBytes, uuidBytes.length + 1)); } /** @@ -52,7 +53,7 @@ final class ProtoTestUtils { System.arraycopy(uuidBytes, 0, concat, 0, uuidBytes.length); System.arraycopy(profileKeyBytes, 0, concat, uuidBytes.length, profileKeyBytes.length); - return ByteString.copyFrom(concat); + return ByteString.of(concat); } /** @@ -60,64 +61,68 @@ final class ProtoTestUtils { * equality assertions in these tests. */ static ByteString presentation(ByteString uuid, ByteString profileKey) { - return uuid.concat(profileKey); + try (Buffer buffer = new Buffer()) { + buffer.write(uuid); + buffer.write(profileKey); + return buffer.readByteString(); + } } static DecryptedModifyMemberRole promoteAdmin(UUID member) { - return DecryptedModifyMemberRole.newBuilder() - .setAciBytes(UuidUtil.toByteString(member)) - .setRole(Member.Role.ADMINISTRATOR) - .build(); + return new DecryptedModifyMemberRole.Builder() + .aciBytes(UuidUtil.toByteString(member)) + .role(Member.Role.ADMINISTRATOR) + .build(); } static DecryptedModifyMemberRole demoteAdmin(UUID member) { - return DecryptedModifyMemberRole.newBuilder() - .setAciBytes(UuidUtil.toByteString(member)) - .setRole(Member.Role.DEFAULT) - .build(); + return new DecryptedModifyMemberRole.Builder() + .aciBytes(UuidUtil.toByteString(member)) + .role(Member.Role.DEFAULT) + .build(); } static Member encryptedMember(UUID uuid, ProfileKey profileKey) { - return Member.newBuilder() - .setPresentation(presentation(uuid, profileKey)) - .build(); + return new Member.Builder() + .presentation(presentation(uuid, profileKey)) + .build(); } static RequestingMember encryptedRequestingMember(UUID uuid, ProfileKey profileKey) { - return RequestingMember.newBuilder() - .setPresentation(presentation(uuid, profileKey)) - .build(); + return new RequestingMember.Builder() + .presentation(presentation(uuid, profileKey)) + .build(); } static DecryptedMember member(UUID uuid) { - return DecryptedMember.newBuilder() - .setAciBytes(UuidUtil.toByteString(uuid)) - .setRole(Member.Role.DEFAULT) - .build(); + return new DecryptedMember.Builder() + .aciBytes(UuidUtil.toByteString(uuid)) + .role(Member.Role.DEFAULT) + .build(); } static DecryptedMember member(UUID uuid, ByteString profileKey, int joinedAtRevision) { - return DecryptedMember.newBuilder() - .setAciBytes(UuidUtil.toByteString(uuid)) - .setRole(Member.Role.DEFAULT) - .setJoinedAtRevision(joinedAtRevision) - .setProfileKey(profileKey) - .build(); + return new DecryptedMember.Builder() + .aciBytes(UuidUtil.toByteString(uuid)) + .role(Member.Role.DEFAULT) + .joinedAtRevision(joinedAtRevision) + .profileKey(profileKey) + .build(); } static DecryptedPendingMemberRemoval pendingMemberRemoval(UUID uuid) { - return DecryptedPendingMemberRemoval.newBuilder() - .setServiceIdBytes(UuidUtil.toByteString(uuid)) - .setServiceIdCipherText(encrypt(uuid)) - .build(); + return new DecryptedPendingMemberRemoval.Builder() + .serviceIdBytes(UuidUtil.toByteString(uuid)) + .serviceIdCipherText(encrypt(uuid)) + .build(); } static DecryptedPendingMember pendingMember(UUID uuid) { - return DecryptedPendingMember.newBuilder() - .setServiceIdBytes(UuidUtil.toByteString(uuid)) - .setServiceIdCipherText(encrypt(uuid)) - .setRole(Member.Role.DEFAULT) - .build(); + return new DecryptedPendingMember.Builder() + .serviceIdBytes(UuidUtil.toByteString(uuid)) + .serviceIdCipherText(encrypt(uuid)) + .role(Member.Role.DEFAULT) + .build(); } static DecryptedRequestingMember requestingMember(UUID uuid) { @@ -125,16 +130,16 @@ final class ProtoTestUtils { } static DecryptedRequestingMember requestingMember(UUID uuid, ProfileKey profileKey) { - return DecryptedRequestingMember.newBuilder() - .setAciBytes(UuidUtil.toByteString(uuid)) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .build(); + return new DecryptedRequestingMember.Builder() + .aciBytes(UuidUtil.toByteString(uuid)) + .profileKey(ByteString.of(profileKey.serialize())) + .build(); } static DecryptedBannedMember bannedMember(UUID uuid) { - return DecryptedBannedMember.newBuilder() - .setServiceIdBytes(UuidUtil.toByteString(uuid)) - .build(); + return new DecryptedBannedMember.Builder() + .serviceIdBytes(UuidUtil.toByteString(uuid)) + .build(); } static DecryptedApproveMember approveMember(UUID uuid) { @@ -146,10 +151,10 @@ final class ProtoTestUtils { } private static DecryptedApproveMember approve(UUID uuid, Member.Role role) { - return DecryptedApproveMember.newBuilder() - .setAciBytes(UuidUtil.toByteString(uuid)) - .setRole(role) - .build(); + return new DecryptedApproveMember.Builder() + .aciBytes(UuidUtil.toByteString(uuid)) + .role(role) + .build(); } static DecryptedMember member(UUID uuid, ProfileKey profileKey) { @@ -157,19 +162,19 @@ final class ProtoTestUtils { } static DecryptedMember pendingPniAciMember(UUID uuid, UUID pni, ProfileKey profileKey) { - return DecryptedMember.newBuilder() - .setAciBytes(UuidUtil.toByteString(uuid)) - .setPniBytes(UuidUtil.toByteString(pni)) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .build(); + return new DecryptedMember.Builder() + .aciBytes(UuidUtil.toByteString(uuid)) + .pniBytes(UuidUtil.toByteString(pni)) + .profileKey(ByteString.of(profileKey.serialize())) + .build(); } static DecryptedMember pendingPniAciMember(ByteString uuid, ByteString pni, ByteString profileKey) { - return DecryptedMember.newBuilder() - .setAciBytes(uuid) - .setPniBytes(pni) - .setProfileKey(profileKey) - .build(); + return new DecryptedMember.Builder() + .aciBytes(uuid) + .pniBytes(pni) + .profileKey(profileKey) + .build(); } static DecryptedMember admin(UUID uuid, ProfileKey profileKey) { @@ -177,30 +182,30 @@ final class ProtoTestUtils { } static DecryptedMember admin(UUID uuid) { - return DecryptedMember.newBuilder() - .setAciBytes(UuidUtil.toByteString(uuid)) - .setRole(Member.Role.ADMINISTRATOR) - .build(); + return new DecryptedMember.Builder() + .aciBytes(UuidUtil.toByteString(uuid)) + .role(Member.Role.ADMINISTRATOR) + .build(); } static DecryptedMember withProfileKey(DecryptedMember member, ProfileKey profileKey) { - return DecryptedMember.newBuilder(member) - .setProfileKey(ByteString.copyFrom(profileKey.serialize())) - .build(); + return member.newBuilder() + .profileKey(ByteString.of(profileKey.serialize())) + .build(); } static DecryptedMember asAdmin(DecryptedMember member) { - return DecryptedMember.newBuilder() - .setAciBytes(member.getAciBytes()) - .setRole(Member.Role.ADMINISTRATOR) - .build(); + return new DecryptedMember.Builder() + .aciBytes(member.aciBytes) + .role(Member.Role.ADMINISTRATOR) + .build(); } static DecryptedMember asMember(DecryptedMember member) { - return DecryptedMember.newBuilder() - .setAciBytes(member.getAciBytes()) - .setRole(Member.Role.DEFAULT) - .build(); + return new DecryptedMember.Builder() + .aciBytes(member.aciBytes) + .role(Member.Role.DEFAULT) + .build(); } public static ProfileKey newProfileKey() { diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtobufTestUtils.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtobufTestUtils.java index f9dc671299..e3d41a4eae 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtobufTestUtils.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtobufTestUtils.java @@ -1,6 +1,7 @@ package org.whispersystems.signalservice.api.groupsv2; -import com.google.protobuf.MessageLite; +import com.squareup.wire.Message; +import com.squareup.wire.WireField; import java.util.stream.Stream; @@ -9,17 +10,12 @@ final class ProtobufTestUtils { /** * Finds the largest declared field number in the supplied protobuf class. */ - static int getMaxDeclaredFieldNumber(Class protobufClass) { + static int getMaxDeclaredFieldNumber(Class> protobufClass) { return Stream.of(protobufClass.getFields()) - .filter(f -> f.getType() == int.class) - .mapToInt(f -> { - try { - return (int) f.get(null); - } catch (IllegalAccessException e) { - throw new AssertionError(e); - } - }) - .max() + .map(f -> f.getAnnotationsByType(WireField.class)) + .filter(a -> a.length == 1) + .map(a -> a[0].tag()) + .max(Integer::compareTo) .orElse(0); } } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/UuidUtilTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/UuidUtilTest.java index b033fbac3f..624e3f4521 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/UuidUtilTest.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/UuidUtilTest.java @@ -1,13 +1,13 @@ package org.whispersystems.signalservice.api.util; -import com.google.protobuf.ByteString; - import org.junit.Test; import org.signal.libsignal.protocol.util.Hex; import java.io.IOException; import java.util.UUID; +import okio.ByteString; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -53,7 +53,7 @@ public final class UuidUtilTest { public void byte_string_round_trip() { UUID uuid = UUID.fromString("67dfd496-ea02-4720-b13d-83a462168b1d"); - UUID result = UuidUtil.fromByteString(ByteString.copyFrom(UuidUtil.toByteArray(uuid))); + UUID result = UuidUtil.fromByteString(ByteString.of(UuidUtil.toByteArray(uuid))); assertEquals(uuid, result); } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java deleted file mode 100644 index 4aebc44e40..0000000000 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.whispersystems.signalservice.internal.serialize; - -import org.junit.Test; -import org.whispersystems.signalservice.api.push.ServiceId; -import org.whispersystems.signalservice.api.push.ServiceId.ACI; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.internal.serialize.protos.AddressProto; - -import java.util.Optional; -import java.util.UUID; - -import static org.junit.Assert.assertEquals; - -public final class SignalServiceAddressProtobufSerializerTest { - - @Test - public void serialize_and_deserialize_uuid_address() { - SignalServiceAddress address = new SignalServiceAddress(ACI.from(UUID.randomUUID()), Optional.empty()); - AddressProto addressProto = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.toProtobuf(address); - SignalServiceAddress deserialized = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.fromProtobuf(addressProto); - - assertEquals(address, deserialized); - } - - @Test - public void serialize_and_deserialize_both_address() { - SignalServiceAddress address = new SignalServiceAddress(ACI.from(UUID.randomUUID()), Optional.of("+15552345678")); - AddressProto addressProto = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.toProtobuf(address); - SignalServiceAddress deserialized = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.fromProtobuf(addressProto); - - assertEquals(address, deserialized); - } -} diff --git a/microbenchmark/build.gradle.kts b/microbenchmark/build.gradle.kts index b7e4f902d7..e3793ef731 100644 --- a/microbenchmark/build.gradle.kts +++ b/microbenchmark/build.gradle.kts @@ -59,5 +59,4 @@ dependencies { // Dependencies of modules being tested androidTestImplementation(project(":libsignal-service")) androidTestImplementation(libs.libsignal.android) - androidTestImplementation(libs.google.protobuf.javalite) } diff --git a/wire-handler/README.md b/wire-handler/README.md new file mode 100644 index 0000000000..ad0e006b4b --- /dev/null +++ b/wire-handler/README.md @@ -0,0 +1,11 @@ +# Build + +`./gradlew build` + +# Move + +`mv lib/build/libs/wire-handler-1.0.0.jar .` + +# Update Signal project + +If version or name changed, update `build.gradle` with new wire-handler jar path in `buildScript/dependencies` diff --git a/wire-handler/gradle b/wire-handler/gradle new file mode 120000 index 0000000000..3337596a26 --- /dev/null +++ b/wire-handler/gradle @@ -0,0 +1 @@ +../gradle \ No newline at end of file diff --git a/wire-handler/gradlew b/wire-handler/gradlew new file mode 120000 index 0000000000..502f5a2d3e --- /dev/null +++ b/wire-handler/gradlew @@ -0,0 +1 @@ +../gradlew \ No newline at end of file diff --git a/wire-handler/gradlew.bat b/wire-handler/gradlew.bat new file mode 120000 index 0000000000..2840132887 --- /dev/null +++ b/wire-handler/gradlew.bat @@ -0,0 +1 @@ +../gradlew.bat \ No newline at end of file diff --git a/wire-handler/lib/build.gradle.kts b/wire-handler/lib/build.gradle.kts new file mode 100644 index 0000000000..f98401b2fa --- /dev/null +++ b/wire-handler/lib/build.gradle.kts @@ -0,0 +1,17 @@ +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName + +plugins { + id("org.jetbrains.kotlin.jvm") version "1.8.10" + `java-library` +} + +version = "1.0.0" +archivesName.set("wire-handler") + +repositories { + mavenCentral() +} + +dependencies { + implementation("com.squareup.wire:wire-schema:4.4.3") +} diff --git a/wire-handler/lib/src/main/kotlin/org/signal/wire/Factory.kt b/wire-handler/lib/src/main/kotlin/org/signal/wire/Factory.kt new file mode 100644 index 0000000000..75ac4eca30 --- /dev/null +++ b/wire-handler/lib/src/main/kotlin/org/signal/wire/Factory.kt @@ -0,0 +1,9 @@ +package org.signal.wire + +import com.squareup.wire.schema.SchemaHandler + +class Factory : SchemaHandler.Factory { + override fun create(): SchemaHandler { + return Handler() + } +} diff --git a/wire-handler/lib/src/main/kotlin/org/signal/wire/Handler.kt b/wire-handler/lib/src/main/kotlin/org/signal/wire/Handler.kt new file mode 100644 index 0000000000..576317ed59 --- /dev/null +++ b/wire-handler/lib/src/main/kotlin/org/signal/wire/Handler.kt @@ -0,0 +1,54 @@ +package org.signal.wire + +import com.squareup.wire.schema.* +import okio.Path +import okio.Path.Companion.toPath +import java.lang.UnsupportedOperationException +import java.nio.charset.Charset + +/** + * Iterate over all generated kotlin files and inline replace calls to countNonNull with calls to + * a 'to be defined' where the proto is used implementation of 'countNonDefa' (short for countNonDefault). + * This code runs as part of wire compilation via the gradle plugin system. + * + * To make the replacement easier, the new name is the same number of bytes as the old to allow using a + * seeking read/write file descriptor to making the updates. + * + * The algorithm for searching/replacing is basic and could be optimized if necessary for faster build times. + */ +class Handler : SchemaHandler() { + + companion object { + private val CHECK_FUNCTION = "countNonNull".encodeToByteArray() + private val REPLACEMENT = "countNonDefa".encodeToByteArray() + } + + override fun handle(schema: Schema, context: Context) { + context.fileSystem + .listRecursively(context.outDirectory) + .filter { it.name.endsWith("kt") } + .forEach { path: Path -> + val readInput = ByteArray(CHECK_FUNCTION.size) + context.fileSystem.openReadWrite(path, mustCreate = false, mustExist = true).use { + var fileOffset = 0L + + var read = it.read(fileOffset = fileOffset, array = readInput, arrayOffset = 0, byteCount = readInput.size) + while (read >= 0) { + if (readInput.contentEquals(CHECK_FUNCTION)) { + it.write(fileOffset = fileOffset, array = REPLACEMENT, arrayOffset = 0, byteCount = REPLACEMENT.size) + fileOffset += REPLACEMENT.size + } else { + fileOffset++ + } + read = it.read(fileOffset = fileOffset, array = readInput, arrayOffset = 0, byteCount = readInput.size) + } + } + } + } + + override fun handle(extend: Extend, field: Field, context: Context): Path = throw UnsupportedOperationException() + + override fun handle(service: Service, context: Context): List = throw UnsupportedOperationException() + + override fun handle(type: Type, context: Context): Path = throw UnsupportedOperationException() +} diff --git a/wire-handler/settings.gradle.kts b/wire-handler/settings.gradle.kts new file mode 100644 index 0000000000..5557c95ff5 --- /dev/null +++ b/wire-handler/settings.gradle.kts @@ -0,0 +1,11 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/8.0.2/userguide/multi_project_builds.html + */ + +rootProject.name = "wire-handler" +include("lib") diff --git a/wire-handler/wire-handler-1.0.0.jar b/wire-handler/wire-handler-1.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..aa90b2e6b84ac1413aa1585118f88aff670e2c57 GIT binary patch literal 6180 zcmaJ_Wmr|)76k+Zqz`@Qk~)Nhgn)EOr-$x3beE(w91%ns4;|7W-6bs`-6*GrdjTbunW9PAif)S@E?itA__8+5~^yf@{&jL{e92mK&+oI|>mZYs+g0KaqWZtNkUD0pN~==x)&bOy*|kXbQ40v^9a4ID?FX#D{|;`$N9;KSdcs44s_TG_~CT6ZkjLCSF-FkVulBUMVjIS90T4 zMB%8)bz%bJ$!Cfa#Te&QC=qQHbGnUBVDHT~r=Ho)C`50qfZq?1nOR&T&?RGx+V2wV zPki3P$Rwg;3V(-!$Cnul!j@s7%#Sjcn#+IctDE81Q!R=}K4Bp>?fi{KLHk; zvs2>?yD$|ZyU}G!S6!BKjAKe-D)H4&SZF*P`;8m4D=HmQgAfY0aVw}@G04Ya6}0DN z(@h?Y&=+aGG-YBc(|IbhzKip;s%3h+zCHjSA)BUd)HLf`Q)YE0^eEotIP6PeR;^M=J zvoqRk9d?VE!mC>nE~HPPRhj~hyw>zi7GDm{R+|(SyO7kY+(zm^L0zRWjy_(#bJVA@ zEUblo@3A?L-IkpgOXo<7rV=ot*FG3N7?>3H>%6)ywb(}D>-;?jWW}gC;j(rZg zB+IWX+7PXNOp#d2iFT3SEJ4MkIv4GK;@%)c-laF2YlO8+$dF#urO`JM{pj`SXd_oi zywQou7V`A{>1;momRvRT#Zd&<{NP+z5n1Y7s^GQZlZ1LGy^=St8`P37a)UNFi(sogfmC$YsjW&<`=be5mztPk9*$>(E7Yk+m}4Y8^5jarQmqcZ!V& zs|o@;grm8NxNE z8pYkR5%=+01z3oY_qqB$zi;z;CXoCw3nWD`{U)Y1z_Rd2T4kswETAOMT{8YcqJLXA z=#%ajRs^vK7x+4E!=5HHJOFoX=~TpcHxT_k{ansrCRZ$&c7PMeAIo zfFq=diry=L7p^m+LI{WO^dlU_6dbF-8T1A0*suCI(KgCHpPOcdUjcKY2RP4qk8-#t zY>~Y`t9Dy4X?t&r7v@3Ony$d8SUY))rzQJE%vOwyZ0lNW%1cCxM5}qW`c0YB*(eTl z{bgKs8)mzROyNxKFLa3~-r6^M56XP>V(bo|O6{|YQ~S8haZU)?F>gk;NH3kW>wSai z${8M_8;=5od?nH+Sx3^;=eMRiwz)8H?U3iM4nhXZ1jYB3!`(KPcx~@K;n`An8!|nt z$tk$40<=!DK9nZ#BmW4t!tAdMdhJ*ie9+>5&%@42Ow^{>Mz7+9v314tY`LY6O@2D*T!?;E-$EFpVzwB1`}1QP=0=Fl{+ozWBIu) zY0K&&C%FL+Ssok+(}ojJKu@uEp6?xYC$`RGoJ4IJKqFs$Zpp)Gr5`Uk{=IFu-#G1jm(y$?(GO0u+jtDq#z@e0eq z-1s=>PeQcMN(4hLI78)O9=L8NEzPjJO|n_KVK6DkSte))8lBBl z_Q-RDY>42%*K*3 zOw%+X*(cJIT5AQIii}gkCQ~_#SGJ8riyZJ zER8GCdRv;sI4zF70rAR9eL1@))Pn1F^-AN+Pm%9MXmf2QMf3WRBFc+MdZgr_0I%YA z6l-YSXylruBid^FNJtKYX==lo?+u^~8LhyGw|Z1Z`^#gCCLi$;(S~DsGSTtlg|~W} z+ko*pa=n+*&O6p!p6`VOvh?iFu7ZzL(h0dohp?M^0v|adH(Ka?(mJ3cywYE<_=w?uy5HY)oBz#?^;n|D7Sf|Pvd4!t4Vvo4 zofBr%j(RR_lZyqav6<=0xoB+5begG5LzvAjLq0CikB%nSx6^D6$9VOmqoN+<9Xy&# zERlpifN$WB9pkC%_X94phxsf&Y4RahC_0;`ec?? zR(yUf?uPTCOWZ4<{vjVv9cf|M^ZXl$tF)C{MN`v#xcio+6rKJJcVtqU?5<5%m_* z09nBYKD5!XZ`76aczc%acz$yw{6h+VSCQ>a&aqT?qPhRxpQWCpp|P`_qX+9>QZGtX zP7$Dtce5Mk+FL1|j{-W&F^cHLi)0=XmqDS!2XN5l6wYj7G@5!!ZOmuvUTEvoj^T&V z=NN86AEhNKbeu`oB^;&f378M^9bI?7wSyyHVr@6VCa(pPGw#;gnKI0h?Iu!s+XZsq zd0qw83u#L29=R&IcS(jD&ONv&e!;m2BWfTIten92*(L9=dRrLH*4E3G!zH#3QyY0= zCarEA;xXC7pU}qD9=9nwpk#ZK3k9`#!WJdj->X{>e6#{s(V6X_j$+oTO|Qu!1p|p+ zHBuy8`|sIZuN(mofJpb9lmiQ6)hiuh42wNTiS(IH6WJTuF>=u~ZfPaj&0=~a5zu!M zmiJ6nKY!eUu+LIpL`18XcPYBQmueresImM!HTrETBvQTfr2OUBYxVSLUEa$C8L46U z;EN!!{1j*<|2gTA@}ZvF4(B8)YGAC^c6ac24VklrScQCk$IZJ1f+e~66GjyXGWjW% z2Lp{TDr++l1I=XyOd%^C&(pDqv|v(6HfTm@0{m*56ftlZAn-^u9}yQJr-hoU4E_#0i(Hk?xQ=n{$VJ0zP3l{uM60FzpgJed)MLqGb>YW6qsOE?6b zEBY!;HY=~xw^m>-(_-ReUdp@vgVD?t1ItzaJxL#q4bC4Q(y$ zZ2#`EH!9kS01>2VF|MfQ>e+mqG`p(L*M4CQIx!r*AaYsRAn+RQiljibK%L(TSZ3 zaDzJ!g>&sVAS`c_V^H6m3=L{GjYxJ?--daEreUbmsR=c@kCk}NZe{YMX-L{o+T6EislpPt`K()7l7gC5d9-u$%3Al!XA%$3SWewx zGY9U2$bj(;Pl}W&Tl3hGitZ`WJs)Qe|2-%{ibqqL$7iqfve1dI*j(T4k6o_Txn9v% z$Vmmx8SQ_w*pT4nW%#O2EO`eq*U0zjt zUCmQKXU(KM)==bP5(JAv<@sVp%uMTH+l(f-OJLfh9)C65IMkz?wI)$+i>6>425DOG zGjxCIugvv`vgGx~J;xjB#@BQ@yMaEUB)V-3pGjwP`sHLE+XI|xVp(-sbPu5@6q)mF zR4KS!atREExT<(Yb>f`nn60?|M!VQkhg95oBG}9RUPkUkamD}^r=`4Uij0OD2(c&$_K9l;$-P?5nh9{Bo3S% zlb&%VqH>xe9E0teTL?XlJ2gL5!8w35-$HNbCLC*rOc+{oGO(OjFLy3)PSS*LJkNlB zs%OE5W5-)a3k3qRth41$lzE3zlRynRG_y_sexmkc$I&;{Yk2VjMFDHlON=*<>_Fr0 zWv4cb_RlP9qxBQQ6acZNA1rHM_UZ71ubIv-AtehOw>_VzLUIewjX0HTc9QB-sdMcUX-AMh&4GQ^3ICzb4t3DsB&6I^xAIzdelfY#ro)vYv_-& zw~M~;_Os6}%YUNNuQCZ#Xj+98?Rf@9R_frDFOAo^96Fg!*dTuuim{{Ttsf!qnIz;f zbAn`sTiVX3%b|tyLOJe9**i1%I|Rp`4?J;C$!>Z+xbl+4Wq~93+0b@4n}l4qgKREP z8bL%;4IjEnEAwEUdK2Kz@e;M6qqGq#Fgh09QyT{o68B9cvaP$&eV~QeJ=K1SR!0HX zJV=hwwy#J1HegKTIu1u+KvTWa;GuwT!mu$$TFoh&i}D}{9+ynd)Q;* zYN13vGEQ`vQJ1W(e0c;a^$lf`4sG{jKRv?e{TjR~+FtY-p2~t~wCtSruTOQrMw4&S z_a=rcb-DzQS(nhbMHKfqNq0BeBvnYndWeRfa!Ok(Djh*qVZ-$D0;HN&qS<(t2smLoIn0KM6E&+=36=aDqS&f(Dj)*`d6&>nD>ibeDAM4lehO{v z0V30P!@nt7=vCVAO)0^~n zm;nPzxAd7blosLv=#t_><5_av(?zK25)-Q@q^B%R77@>@*dh6{wmfWyuFe!p+R=H4 zMG{LAagCY?Qecp>BY(Udj^)M5IH2|{tT5LG2x_0kD9cHT2vzg=k_PUj* zQhoK8G5%5nQ3XKvoP@HtbHNz@TA?mZM2}55=!beMZ_(Njvc3eYyY(VSp1} zS_7Ucsa5XePr`ZmZ3^&arB!UaXhp(sE9Gp^jkNW=y5C`prF5+y7s9|4EvMU`aSu3 zWcf4R&Hsh{F@e8!@t|DKNJ4$oPKv#{|;=pYmwf&$M0V2|3iHD zTK|skh~2x#?}&e#*PnrZa$bJ`iQ#_%{^i5|j{e<;{pY=RmCO7A{fjI6Gu5AT{tqgy zyMlhI;ID=JqWXWP`jf2tLG=pbf2sai)$bzjchcW??;oT$SpQD?>t3!ThlKnchjw?B N-|0@BJNp_A?ms9Ar;`8x literal 0 HcmV?d00001