From 6a211063471c615a7c1fe0d85a80eee88c023c68 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Mon, 28 Aug 2023 22:47:02 -0400 Subject: [PATCH] Convert StorageService protos to wire. --- .../changenumber/ChangeNumberViewModelTest.kt | 1 - ...TableTest_applyStorageSyncContactUpdate.kt | 4 +- .../storage/ContactRecordProcessorTest.kt | 50 ++-- .../securesms/database/RecipientTable.kt | 2 +- .../securesms/jobs/StorageSyncJob.java | 23 +- .../ApplyUnknownFieldsToSelfMigrationJob.java | 6 +- .../securesms/storage/StorageSyncHelper.java | 21 +- .../storage/StorageSyncValidations.java | 10 +- .../storage/ContactRecordProcessorTest.kt | 228 ++++++++++------- ...toryDistributionListRecordProcessorTest.kt | 70 +++--- .../api/SignalServiceAccountManager.java | 128 +++++----- .../api/storage/SignalAccountRecord.java | 195 +++++++------- .../api/storage/SignalContactRecord.java | 100 ++++---- .../api/storage/SignalGroupV1Record.java | 40 +-- .../api/storage/SignalGroupV2Record.java | 52 ++-- .../api/storage/SignalStorageManifest.java | 48 ++-- .../api/storage/SignalStorageModels.java | 64 ++--- .../SignalStoryDistributionListRecord.java | 45 ++-- .../signalservice/api/storage/StorageId.java | 16 +- .../api/storage/StorageRecordProtoUtil.kt | 18 ++ .../signalservice/api/util/OptionalUtil.kt | 4 +- .../signalservice/api/util/ProtoUtil.java | 52 ++-- .../signalservice/api/util/UuidUtil.java | 4 + .../crypto/PrimaryProvisioningCipher.java | 1 - .../internal/push/PushServiceSocket.java | 13 +- .../{proto => protowire}/StorageService.proto | 0 .../signalservice/api/util/ProtoUtilTest.java | 237 ------------------ libsignal/service/src/test/proto/Test.proto | 70 ------ 28 files changed, 620 insertions(+), 882 deletions(-) create mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageRecordProtoUtil.kt rename libsignal/service/src/main/{proto => protowire}/StorageService.proto (100%) delete mode 100644 libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/ProtoUtilTest.java delete mode 100644 libsignal/service/src/test/proto/Test.proto diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt index 4757e4f830..a6640d660e 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt @@ -50,7 +50,6 @@ class ChangeNumberViewModelTest { @Before fun setUp() { - ApplicationDependencies.getSignalServiceAccountManager().setSoTimeoutMillis(1000) ThreadUtil.runOnMainSync { viewModel = ChangeNumberViewModel( localNumber = harness.self.requireE164(), diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_applyStorageSyncContactUpdate.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_applyStorageSyncContactUpdate.kt index 9052393f02..a795cfbab3 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_applyStorageSyncContactUpdate.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_applyStorageSyncContactUpdate.kt @@ -38,8 +38,8 @@ class RecipientTableTest_applyStorageSyncContactUpdate { val newProto = oldRecord .toProto() - .toBuilder() - .setIdentityState(ContactRecord.IdentityState.DEFAULT) + .newBuilder() + .identityState(ContactRecord.IdentityState.DEFAULT) .build() val newRecord = SignalContactRecord(oldRecord.id, newProto) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt index ed0565ac14..f7073635cc 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt @@ -38,15 +38,21 @@ class ContactRecordProcessorTest { val originalId = SignalDatabase.recipients.getAndPossiblyMerge(ACI_A, PNI_A, E164_A) setStorageId(originalId, STORAGE_ID_A) - val remote1 = buildRecord(STORAGE_ID_B) { - setAci(ACI_A.toString()) - setUnregisteredAtTimestamp(100) - } + val remote1 = buildRecord( + STORAGE_ID_B, + ContactRecord( + aci = ACI_A.toString(), + unregisteredAtTimestamp = 100 + ) + ) - val remote2 = buildRecord(STORAGE_ID_C) { - setPni(PNI_A.toString()) - setE164(E164_A) - } + val remote2 = buildRecord( + STORAGE_ID_C, + ContactRecord( + pni = PNI_A.toString(), + e164 = E164_A + ) + ) // WHEN val subject = ContactRecordProcessor() @@ -69,16 +75,22 @@ class ContactRecordProcessorTest { val originalId = SignalDatabase.recipients.getAndPossiblyMerge(ACI_A, PNI_A, E164_A) setStorageId(originalId, STORAGE_ID_A) - val remote1 = buildRecord(STORAGE_ID_B) { - setAci(ACI_A.toString()) - setUnregisteredAtTimestamp(0) - } + val remote1 = buildRecord( + STORAGE_ID_B, + ContactRecord( + aci = ACI_A.toString(), + unregisteredAtTimestamp = 0 + ) + ) - val remote2 = buildRecord(STORAGE_ID_C) { - setAci(PNI_A.toString()) - setPni(PNI_A.toString()) - setE164(E164_A) - } + val remote2 = buildRecord( + STORAGE_ID_C, + ContactRecord( + aci = PNI_A.toString(), + pni = PNI_A.toString(), + e164 = E164_A + ) + ) // WHEN val subject = ContactRecordProcessor() @@ -94,8 +106,8 @@ class ContactRecordProcessorTest { assertEquals(byAci, byE164) } - private fun buildRecord(id: StorageId, applyParams: ContactRecord.Builder.() -> ContactRecord.Builder): SignalContactRecord { - return SignalContactRecord(id, ContactRecord.getDefaultInstance().toBuilder().applyParams().build()) + private fun buildRecord(id: StorageId, record: ContactRecord): SignalContactRecord { + return SignalContactRecord(id, record) } private fun setStorageId(recipientId: RecipientId, storageId: StorageId) { 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 573028056f..f16cfaa8f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -1069,7 +1069,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da GroupV2Record.StorySendMode.DEFAULT -> ShowAsStoryState.IF_ACTIVE GroupV2Record.StorySendMode.DISABLED -> ShowAsStoryState.NEVER GroupV2Record.StorySendMode.ENABLED -> ShowAsStoryState.ALWAYS - GroupV2Record.StorySendMode.UNRECOGNIZED -> ShowAsStoryState.IF_ACTIVE + else -> ShowAsStoryState.IF_ACTIVE } } 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 f00052e49b..c99e1a6898 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.java @@ -412,7 +412,7 @@ public class StorageSyncJob extends BaseJob { new GroupV2RecordProcessor(context).process(records.gv2, StorageSyncHelper.KEY_GENERATOR); new AccountRecordProcessor(context, freshSelf()).process(records.account, StorageSyncHelper.KEY_GENERATOR); - if (getKnownTypes().contains(ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST_VALUE)) { + if (getKnownTypes().contains(ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST.getValue())) { new StoryDistributionListRecordProcessor().process(records.storyDistributionLists, StorageSyncHelper.KEY_GENERATOR); } } @@ -434,10 +434,15 @@ public class StorageSyncJob extends BaseJob { List records = new ArrayList<>(ids.size()); for (StorageId id : ids) { - switch (id.getType()) { - case ManifestRecord.Identifier.Type.CONTACT_VALUE: - case ManifestRecord.Identifier.Type.GROUPV1_VALUE: - case ManifestRecord.Identifier.Type.GROUPV2_VALUE: + ManifestRecord.Identifier.Type type = ManifestRecord.Identifier.Type.fromValue(id.getType()); + if (type == null) { + type = ManifestRecord.Identifier.Type.UNKNOWN; + } + + switch (type) { + case CONTACT: + case GROUPV1: + case GROUPV2: RecipientRecord settings = recipientTable.getByStorageId(id.getRaw()); if (settings != null) { if (settings.getRecipientType() == RecipientTable.RecipientType.GV2 && settings.getSyncExtras().getGroupMasterKey() == null) { @@ -449,13 +454,13 @@ public class StorageSyncJob extends BaseJob { throw new MissingRecipientModelError("Missing local recipient model! Type: " + id.getType()); } break; - case ManifestRecord.Identifier.Type.ACCOUNT_VALUE: + case ACCOUNT: if (!Arrays.equals(self.getStorageServiceId(), id.getRaw())) { throw new AssertionError("Local storage ID doesn't match self!"); } records.add(StorageSyncHelper.buildAccountRecord(context, self)); break; - case ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST_VALUE: + case STORY_DISTRIBUTION_LIST: RecipientRecord record = recipientTable.getByStorageId(id.getRaw()); if (record != null) { if (record.getDistributionListId() != null) { @@ -488,8 +493,8 @@ public class StorageSyncJob extends BaseJob { private static List getKnownTypes() { return Arrays.stream(ManifestRecord.Identifier.Type.values()) - .filter(it -> !it.equals(ManifestRecord.Identifier.Type.UNKNOWN) && !it.equals(ManifestRecord.Identifier.Type.UNRECOGNIZED)) - .map(it -> it.getNumber()) + .filter(it -> !it.equals(ManifestRecord.Identifier.Type.UNKNOWN)) + .map(ManifestRecord.Identifier.Type::getValue) .collect(Collectors.toList()); } 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 bb2ba98153..26a70fc669 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplyUnknownFieldsToSelfMigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplyUnknownFieldsToSelfMigrationJob.java @@ -17,6 +17,8 @@ import org.whispersystems.signalservice.api.storage.SignalAccountRecord; import org.whispersystems.signalservice.api.storage.StorageId; import org.whispersystems.signalservice.internal.storage.protos.AccountRecord; +import java.io.IOException; + /** * Check for unknown fields stored on self and attempt to apply them. */ @@ -69,12 +71,12 @@ public class ApplyUnknownFieldsToSelfMigrationJob extends MigrationJob { try { StorageId storageId = StorageId.forAccount(self.getStorageServiceId()); - AccountRecord accountRecord = AccountRecord.parseFrom(settings.getSyncExtras().getStorageProto()); + AccountRecord accountRecord = AccountRecord.ADAPTER.decode(settings.getSyncExtras().getStorageProto()); SignalAccountRecord signalAccountRecord = new SignalAccountRecord(storageId, accountRecord); Log.d(TAG, "Applying potentially now known unknowns"); StorageSyncHelper.applyAccountStorageSyncUpdates(context, self, signalAccountRecord, false); - } catch (InvalidProtocolBufferException e) { + } catch (IOException e) { Log.w(TAG, e); } } 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 e4a61ad11a..df0ffdeee6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncHelper.java @@ -8,11 +8,9 @@ import androidx.annotation.VisibleForTesting; 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; -import org.thoughtcrime.securesms.components.settings.app.usernamelinks.UsernameQrCodeColorScheme; import org.thoughtcrime.securesms.database.RecipientTable; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.RecipientRecord; @@ -31,7 +29,6 @@ import org.thoughtcrime.securesms.util.Util; import org.whispersystems.signalservice.api.push.UsernameLinkComponents; import org.whispersystems.signalservice.api.storage.SignalAccountRecord; import org.whispersystems.signalservice.api.storage.SignalContactRecord; -import org.whispersystems.signalservice.api.storage.SignalRecord; import org.whispersystems.signalservice.api.storage.SignalStorageManifest; import org.whispersystems.signalservice.api.storage.SignalStorageRecord; import org.whispersystems.signalservice.api.storage.StorageId; @@ -49,6 +46,8 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import okio.ByteString; + public final class StorageSyncHelper { private static final String TAG = Log.tag(StorageSyncHelper.class); @@ -167,11 +166,11 @@ public final class StorageSyncHelper { UsernameLinkComponents linkComponents = SignalStore.account().getUsernameLink(); if (linkComponents != null) { - account.setUsernameLink(AccountRecord.UsernameLink.newBuilder() - .setEntropy(ByteString.copyFrom(linkComponents.getEntropy())) - .setServerId(UuidUtil.toByteString(linkComponents.getServerId())) - .setColor(StorageSyncModels.localToRemoteUsernameColor(SignalStore.misc().getUsernameQrCodeColorScheme())) - .build()); + account.setUsernameLink(new AccountRecord.UsernameLink.Builder() + .entropy(ByteString.of(linkComponents.getEntropy())) + .serverId(UuidUtil.toOkioByteString(linkComponents.getServerId())) + .color(StorageSyncModels.localToRemoteUsernameColor(SignalStore.misc().getUsernameQrCodeColorScheme())) + .build()); } else { account.setUsernameLink(null); } @@ -235,11 +234,11 @@ public final class StorageSyncHelper { if (update.getNew().getUsernameLink() != null) { SignalStore.account().setUsernameLink( new UsernameLinkComponents( - update.getNew().getUsernameLink().getEntropy().toByteArray(), - UuidUtil.parseOrThrow(update.getNew().getUsernameLink().getServerId().toByteArray()) + update.getNew().getUsernameLink().entropy.toByteArray(), + UuidUtil.parseOrThrow(update.getNew().getUsernameLink().serverId.toByteArray()) ) ); - SignalStore.misc().setUsernameQrCodeColorScheme(StorageSyncModels.remoteToLocalUsernameColor(update.getNew().getUsernameLink().getColor())); + SignalStore.misc().setUsernameQrCodeColorScheme(StorageSyncModels.remoteToLocalUsernameColor(update.getNew().getUsernameLink().color)); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncValidations.java b/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncValidations.java index cdee9515ba..2a22af49af 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncValidations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/storage/StorageSyncValidations.java @@ -104,7 +104,7 @@ public final class StorageSyncValidations { private static void validateManifestAndInserts(@NonNull SignalStorageManifest manifest, @NonNull List inserts, @NonNull Recipient self) { int accountCount = 0; for (StorageId id : manifest.getStorageIds()) { - accountCount += id.getType() == ManifestRecord.Identifier.Type.ACCOUNT_VALUE ? 1 : 0; + accountCount += id.getType() == ManifestRecord.Identifier.Type.ACCOUNT.getValue() ? 1 : 0; } if (accountCount > 1) { @@ -124,22 +124,22 @@ public final class StorageSyncValidations { } if (rawIdSet.size() != allSet.size()) { - List ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.CONTACT_VALUE); + List ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.CONTACT.getValue()); if (ids.size() != new HashSet<>(ids).size()) { throw new DuplicateContactIdError(); } - ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.GROUPV1_VALUE); + ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.GROUPV1.getValue()); if (ids.size() != new HashSet<>(ids).size()) { throw new DuplicateGroupV1IdError(); } - ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.GROUPV2_VALUE); + ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.GROUPV2.getValue()); if (ids.size() != new HashSet<>(ids).size()) { throw new DuplicateGroupV2IdError(); } - ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST_VALUE); + ids = manifest.getStorageIdsByType().get(ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST.getValue()); if (ids.size() != new HashSet<>(ids).size()) { throw new DuplicateDistributionListIdError(); } diff --git a/app/src/test/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt b/app/src/test/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt index c42ffb2a2d..79ac3b8e02 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt @@ -55,11 +55,13 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setPni(PNI_B.toStringWithoutPrefix()) - setE164(E164_B) - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + pni = PNI_B.toStringWithoutPrefix(), + e164 = E164_B + ) + ) // WHEN val result = subject.isInvalid(record) @@ -73,9 +75,11 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setE164(E164_B) - } + val record = buildRecord( + record = ContactRecord( + e164 = E164_B + ) + ) // WHEN val result = subject.isInvalid(record) @@ -89,11 +93,13 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI.UNKNOWN.toString()) - setPni(PNI.UNKNOWN.toString()) - setE164(E164_B) - } + val record = buildRecord( + record = ContactRecord( + aci = ACI.UNKNOWN.toString(), + pni = PNI.UNKNOWN.toString(), + e164 = E164_B + ) + ) // WHEN val result = subject.isInvalid(record) @@ -107,10 +113,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setE164(E164_A) - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + e164 = E164_A + ) + ) // WHEN val result = subject.isInvalid(record) @@ -124,9 +132,11 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_A.toString()) - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_A.toString() + ) + ) // WHEN val result = subject.isInvalid(record) @@ -140,10 +150,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setPni(PNI_A.toStringWithoutPrefix()) - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + pni = PNI_A.toStringWithoutPrefix() + ) + ) // WHEN val result = subject.isInvalid(record) @@ -157,10 +169,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setE164(E164_B) - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + e164 = E164_B + ) + ) // WHEN val result = subject.isInvalid(record) @@ -174,10 +188,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setE164("15551234567") - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + e164 = "15551234567" + ) + ) // WHEN val result = subject.isInvalid(record) @@ -191,10 +207,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setE164("+1555ABC4567") - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + e164 = "+1555ABC4567" + ) + ) // WHEN val result = subject.isInvalid(record) @@ -208,10 +226,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setE164("+") - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + e164 = "+" + ) + ) // WHEN val result = subject.isInvalid(record) @@ -225,10 +245,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setE164("+12345678901234567890") - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + e164 = "+12345678901234567890" + ) + ) // WHEN val result = subject.isInvalid(record) @@ -242,10 +264,12 @@ class ContactRecordProcessorTest { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - val record = buildRecord { - setAci(ACI_B.toString()) - setE164("+05551234567") - } + val record = buildRecord( + record = ContactRecord( + aci = ACI_B.toString(), + e164 = "+05551234567" + ) + ) // WHEN val result = subject.isInvalid(record) @@ -261,17 +285,23 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(true) - val local = buildRecord(STORAGE_ID_A) { - setAci(ACI_A.toString()) - setE164(E164_A) - setPni(PNI_A.toStringWithoutPrefix()) - } + val local = buildRecord( + STORAGE_ID_A, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_A, + pni = PNI_A.toStringWithoutPrefix() + ) + ) - val remote = buildRecord(STORAGE_ID_B) { - setAci(ACI_A.toString()) - setE164(E164_A) - setPni(PNI_B.toStringWithoutPrefix()) - } + val remote = buildRecord( + STORAGE_ID_B, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_A, + pni = PNI_B.toStringWithoutPrefix() + ) + ) // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) @@ -289,17 +319,23 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(true) - val local = buildRecord(STORAGE_ID_A) { - setAci(ACI_A.toString()) - setE164(E164_A) - setPni(PNI_A.toStringWithoutPrefix()) - } + val local = buildRecord( + STORAGE_ID_A, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_A, + pni = PNI_A.toStringWithoutPrefix() + ) + ) - val remote = buildRecord(STORAGE_ID_B) { - setAci(ACI_A.toString()) - setE164(E164_B) - setPni(PNI_A.toStringWithoutPrefix()) - } + val remote = buildRecord( + STORAGE_ID_B, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_B, + pni = PNI_A.toStringWithoutPrefix() + ) + ) // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) @@ -317,17 +353,23 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(true) - val local = buildRecord(STORAGE_ID_A) { - setAci(ACI_A.toString()) - setE164(E164_A) - setPni(PNI_A.toStringWithoutPrefix()) - } + val local = buildRecord( + STORAGE_ID_A, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_A, + pni = PNI_A.toStringWithoutPrefix() + ) + ) - val remote = buildRecord(STORAGE_ID_B) { - setAci(ACI_A.toString()) - setE164(E164_B) - setPni(PNI_B.toStringWithoutPrefix()) - } + val remote = buildRecord( + STORAGE_ID_B, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_B, + pni = PNI_B.toStringWithoutPrefix() + ) + ) // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) @@ -345,17 +387,23 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(false) - val local = buildRecord(STORAGE_ID_A) { - setAci(ACI_A.toString()) - setE164(E164_A) - setPni(PNI_A.toStringWithoutPrefix()) - } + val local = buildRecord( + STORAGE_ID_A, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_A, + pni = PNI_A.toStringWithoutPrefix() + ) + ) - val remote = buildRecord(STORAGE_ID_B) { - setAci(ACI_A.toString()) - setE164(E164_B) - setPni(PNI_B.toStringWithoutPrefix()) - } + val remote = buildRecord( + STORAGE_ID_B, + record = ContactRecord( + aci = ACI_A.toString(), + e164 = E164_B, + pni = PNI_B.toStringWithoutPrefix() + ) + ) // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) @@ -366,8 +414,8 @@ class ContactRecordProcessorTest { assertEquals(false, result.pni.isPresent) } - private fun buildRecord(id: StorageId = STORAGE_ID_A, applyParams: ContactRecord.Builder.() -> ContactRecord.Builder): SignalContactRecord { - return SignalContactRecord(id, ContactRecord.getDefaultInstance().toBuilder().applyParams().build()) + private fun buildRecord(id: StorageId = STORAGE_ID_A, record: ContactRecord): SignalContactRecord { + return SignalContactRecord(id, record) } private class TestKeyGenerator(private val value: StorageId) : StorageKeyGenerator { diff --git a/app/src/test/java/org/thoughtcrime/securesms/storage/StoryDistributionListRecordProcessorTest.kt b/app/src/test/java/org/thoughtcrime/securesms/storage/StoryDistributionListRecordProcessorTest.kt index 53bb09f57f..8145495e65 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/storage/StoryDistributionListRecordProcessorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/storage/StoryDistributionListRecordProcessorTest.kt @@ -1,6 +1,6 @@ package org.thoughtcrime.securesms.storage -import com.google.protobuf.ByteString +import okio.ByteString import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.BeforeClass @@ -31,7 +31,7 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto without an identifier, when I isInvalid, then I expect true`() { // GIVEN - val proto = StoryDistributionListRecord.getDefaultInstance() + val proto = StoryDistributionListRecord() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) // WHEN @@ -44,10 +44,9 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto with an identifier that is not a UUID, when I isInvalid, then I expect true`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(ByteString.copyFrom("Greetings, fellow UUIDs".encodeToByteArray())) + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*"Greetings, fellow UUIDs".encodeToByteArray())) .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) @@ -62,10 +61,9 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto without a name or deletion timestamp, when I isInvalid, then I expect true`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(UuidUtil.toByteString(UUID.randomUUID())) + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*UuidUtil.toByteArray(UUID.randomUUID()))) .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) @@ -80,11 +78,10 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto with a deletion timestamp, when I isInvalid, then I expect false`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(UuidUtil.toByteString(UUID.randomUUID())) - .setDeletedAtTimestamp(1) + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*UuidUtil.toByteArray(UUID.randomUUID()))) + .deletedAtTimestamp(1) .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) @@ -99,11 +96,10 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto that is MyStory with a deletion timestamp, when I isInvalid, then I expect true`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(UuidUtil.toByteString(DistributionId.MY_STORY.asUuid())) - .setDeletedAtTimestamp(1) + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*UuidUtil.toByteArray(DistributionId.MY_STORY.asUuid()))) + .deletedAtTimestamp(1) .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) @@ -118,11 +114,10 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a validated proto that is MyStory, when I isInvalid with another MyStory, then I expect true`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(UuidUtil.toByteString(DistributionId.MY_STORY.asUuid())) - .setDeletedAtTimestamp(1) + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*UuidUtil.toByteArray(DistributionId.MY_STORY.asUuid()))) + .deletedAtTimestamp(1) .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) @@ -138,11 +133,10 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto with a visible name, when I isInvalid, then I expect false`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(UuidUtil.toByteString(UUID.randomUUID())) - .setName("A visible name") + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*UuidUtil.toByteArray(UUID.randomUUID()))) + .name("A visible name") .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) @@ -157,10 +151,9 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto without a name, when I isInvalid, then I expect false`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(UuidUtil.toByteString(UUID.randomUUID())) + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*UuidUtil.toByteArray(UUID.randomUUID()))) .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) @@ -175,11 +168,10 @@ class StoryDistributionListRecordProcessorTest { @Test fun `Given a proto without a visible name, when I isInvalid, then I expect true`() { // GIVEN - val proto = StoryDistributionListRecord - .getDefaultInstance() - .toBuilder() - .setIdentifier(UuidUtil.toByteString(UUID.randomUUID())) - .setName(" ") + val proto = StoryDistributionListRecord() + .newBuilder() + .identifier(ByteString.of(*UuidUtil.toByteArray(UUID.randomUUID()))) + .name(" ") .build() val record = SignalStoryDistributionListRecord(STORAGE_ID, proto) 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 722a2944ea..87f0c91de7 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 @@ -6,9 +6,6 @@ package org.whispersystems.signalservice.api; - -import com.google.protobuf.ByteString; - import org.signal.libsignal.protocol.IdentityKeyPair; import org.signal.libsignal.protocol.InvalidKeyException; import org.signal.libsignal.protocol.ecc.ECPublicKey; @@ -36,9 +33,9 @@ import org.whispersystems.signalservice.api.payments.CurrencyConversions; import org.whispersystems.signalservice.api.profiles.AvatarUploadParams; import org.whispersystems.signalservice.api.profiles.ProfileAndCredential; import org.whispersystems.signalservice.api.profiles.SignalServiceProfileWrite; +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.ServiceIdType; import org.whispersystems.signalservice.api.push.UsernameLinkComponents; import org.whispersystems.signalservice.api.push.exceptions.NoContentException; @@ -92,7 +89,6 @@ import java.security.KeyStore; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -106,11 +102,13 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; import io.reactivex.rxjava3.core.Single; +import okio.ByteString; /** * The main interface for creating, registering, and @@ -460,7 +458,7 @@ public class SignalServiceAccountManager { String authToken = this.pushServiceSocket.getStorageAuth(); StorageManifest storageManifest = this.pushServiceSocket.getStorageManifest(authToken); - return storageManifest.getVersion(); + return storageManifest.version; } catch (NotFoundException e) { return 0; } @@ -471,7 +469,7 @@ public class SignalServiceAccountManager { String authToken = this.pushServiceSocket.getStorageAuth(); StorageManifest storageManifest = this.pushServiceSocket.getStorageManifestIfDifferentVersion(authToken, manifestVersion); - if (storageManifest.getValue().isEmpty()) { + if (storageManifest.value_.size() == 0) { Log.w(TAG, "Got an empty storage manifest!"); return Optional.empty(); } @@ -487,29 +485,29 @@ public class SignalServiceAccountManager { return Collections.emptyList(); } - List result = new ArrayList<>(); - Map typeMap = new HashMap<>(); - List readOperations = new LinkedList<>(); - ReadOperation.Builder currentOperation = ReadOperation.newBuilder(); + List result = new ArrayList<>(); + Map typeMap = new HashMap<>(); + List readOperations = new LinkedList<>(); + List readKeys = new LinkedList<>(); for (StorageId key : storageKeys) { - typeMap.put(ByteString.copyFrom(key.getRaw()), key.getType()); + typeMap.put(ByteString.of(key.getRaw()), key.getType()); - if (currentOperation.getReadKeyCount() >= STORAGE_READ_MAX_ITEMS) { + if (readKeys.size() >= STORAGE_READ_MAX_ITEMS) { Log.i(TAG, "Going over max read items. Starting a new read operation."); - readOperations.add(currentOperation.build()); - currentOperation = ReadOperation.newBuilder(); + readOperations.add(new ReadOperation.Builder().readKey(readKeys).build()); + readKeys = new LinkedList<>(); } if (StorageId.isKnownType(key.getType())) { - currentOperation.addReadKey(ByteString.copyFrom(key.getRaw())); + readKeys.add(ByteString.of(key.getRaw())); } else { result.add(SignalStorageRecord.forUnknown(key)); } } - if (currentOperation.getReadKeyCount() > 0) { - readOperations.add(currentOperation.build()); + if (readKeys.size() > 0) { + readOperations.add(new ReadOperation.Builder().readKey(readKeys).build()); } Log.i(TAG, "Reading " + storageKeys.size() + " items split over " + readOperations.size() + " page(s)."); @@ -519,8 +517,8 @@ public class SignalServiceAccountManager { for (ReadOperation readOperation : readOperations) { StorageItems items = this.pushServiceSocket.readStorageItems(authToken, readOperation); - for (StorageItem item : items.getItemsList()) { - Integer type = typeMap.get(item.getKey()); + for (StorageItem item : items.items) { + Integer type = typeMap.get(item.key); if (type != null) { result.add(SignalStorageModels.remoteToLocalStorageRecord(item, type, storageKey)); } else { @@ -579,51 +577,59 @@ public class SignalServiceAccountManager { boolean clearAll) throws IOException, InvalidKeyException { - ManifestRecord.Builder manifestRecordBuilder = ManifestRecord.newBuilder() - .setSourceDevice(manifest.getSourceDeviceId()) - .setVersion(manifest.getVersion()); + ManifestRecord.Builder manifestRecordBuilder = new ManifestRecord.Builder() + .sourceDevice(manifest.getSourceDeviceId()) + .version(manifest.getVersion()); - for (StorageId id : manifest.getStorageIds()) { - ManifestRecord.Identifier idProto = ManifestRecord.Identifier.newBuilder() - .setRaw(ByteString.copyFrom(id.getRaw())) - .setTypeValue(id.getType()).build(); - manifestRecordBuilder.addIdentifiers(idProto); - } + + manifestRecordBuilder.identifiers( + manifest.getStorageIds().stream() + .map(id -> new ManifestRecord.Identifier.Builder() + .raw(ByteString.of(id.getRaw())) + .type(ManifestRecord.Identifier.Type.Companion.fromValue(id.getType())) + .build()) + .collect(Collectors.toList()) + ); String authToken = this.pushServiceSocket.getStorageAuth(); StorageManifestKey manifestKey = storageKey.deriveManifestKey(manifest.getVersion()); - byte[] encryptedRecord = SignalStorageCipher.encrypt(manifestKey, manifestRecordBuilder.build().toByteArray()); - StorageManifest storageManifest = StorageManifest.newBuilder() - .setVersion(manifest.getVersion()) - .setValue(ByteString.copyFrom(encryptedRecord)) - .build(); - WriteOperation.Builder writeBuilder = WriteOperation.newBuilder().setManifest(storageManifest); + byte[] encryptedRecord = SignalStorageCipher.encrypt(manifestKey, manifestRecordBuilder.build().encode()); + StorageManifest storageManifest = new StorageManifest.Builder() + .version(manifest.getVersion()) + .value_(ByteString.of(encryptedRecord)) + .build(); - for (SignalStorageRecord insert : inserts) { - writeBuilder.addInsertItem(SignalStorageModels.localToRemoteStorageRecord(insert, storageKey)); - } + WriteOperation.Builder writeBuilder = new WriteOperation.Builder().manifest(storageManifest); + + writeBuilder.insertItem( + inserts.stream() + .map(insert -> SignalStorageModels.localToRemoteStorageRecord(insert, storageKey)) + .collect(Collectors.toList()) + ); if (clearAll) { - writeBuilder.setClearAll(true); + writeBuilder.clearAll(true); } else { - for (byte[] delete : deletes) { - writeBuilder.addDeleteKey(ByteString.copyFrom(delete)); - } + writeBuilder.deleteKey( + deletes.stream() + .map(delete -> ByteString.of(delete)) + .collect(Collectors.toList()) + ); } Optional conflict = this.pushServiceSocket.writeStorageContacts(authToken, writeBuilder.build()); if (conflict.isPresent()) { - StorageManifestKey conflictKey = storageKey.deriveManifestKey(conflict.get().getVersion()); - byte[] rawManifestRecord = SignalStorageCipher.decrypt(conflictKey, conflict.get().getValue().toByteArray()); - ManifestRecord record = ManifestRecord.parseFrom(rawManifestRecord); - List ids = new ArrayList<>(record.getIdentifiersCount()); + StorageManifestKey conflictKey = storageKey.deriveManifestKey(conflict.get().version); + byte[] rawManifestRecord = SignalStorageCipher.decrypt(conflictKey, conflict.get().value_.toByteArray()); + ManifestRecord record = ManifestRecord.ADAPTER.decode(rawManifestRecord); + List ids = new ArrayList<>(record.identifiers.size()); - for (ManifestRecord.Identifier id : record.getIdentifiersList()) { - ids.add(StorageId.forType(id.getRaw().toByteArray(), id.getTypeValue())); + for (ManifestRecord.Identifier id : record.identifiers) { + ids.add(StorageId.forType(id.raw.toByteArray(), id.type.getValue())); } - SignalStorageManifest conflictManifest = new SignalStorageManifest(record.getVersion(), record.getSourceDevice(), ids); + SignalStorageManifest conflictManifest = new SignalStorageManifest(record.version, record.sourceDevice, ids); return Optional.of(conflictManifest); } else { @@ -668,14 +674,14 @@ public class SignalServiceAccountManager { PrimaryProvisioningCipher cipher = new PrimaryProvisioningCipher(deviceKey); ProvisionMessage.Builder message = new ProvisionMessage.Builder() - .aciIdentityKeyPublic(okio.ByteString.of(aciIdentityKeyPair.getPublicKey().serialize())) - .aciIdentityKeyPrivate(okio.ByteString.of(aciIdentityKeyPair.getPrivateKey().serialize())) - .pniIdentityKeyPublic(okio.ByteString.of(pniIdentityKeyPair.getPublicKey().serialize())) - .pniIdentityKeyPrivate(okio.ByteString.of(pniIdentityKeyPair.getPrivateKey().serialize())) + .aciIdentityKeyPublic(ByteString.of(aciIdentityKeyPair.getPublicKey().serialize())) + .aciIdentityKeyPrivate(ByteString.of(aciIdentityKeyPair.getPrivateKey().serialize())) + .pniIdentityKeyPublic(ByteString.of(pniIdentityKeyPair.getPublicKey().serialize())) + .pniIdentityKeyPrivate(ByteString.of(pniIdentityKeyPair.getPrivateKey().serialize())) .aci(aci.toString()) .pni(pni.toStringWithoutPrefix()) .number(e164) - .profileKey(okio.ByteString.of(profileKey.serialize())) + .profileKey(ByteString.of(profileKey.serialize())) .provisioningCode(code) .provisioningVersion(ProvisioningVersion.CURRENT.getValue()); @@ -827,10 +833,6 @@ public class SignalServiceAccountManager { this.pushServiceSocket.submitRateLimitRecaptchaChallenge(challenge, recaptchaToken); } - public void setSoTimeoutMillis(long soTimeoutMillis) { - this.pushServiceSocket.setSoTimeoutMillis(soTimeoutMillis); - } - public void cancelInFlightRequests() { this.pushServiceSocket.cancelInFlightRequests(); } @@ -848,16 +850,6 @@ public class SignalServiceAccountManager { } } - private Map createDirectoryServerTokenMap(Collection e164numbers) { - Map tokenMap = new HashMap<>(e164numbers.size()); - - for (String number : e164numbers) { - tokenMap.put(createDirectoryServerToken(number, false), number); - } - - return tokenMap; - } - public GroupsV2Api getGroupsV2Api() { return new GroupsV2Api(pushServiceSocket, groupsV2Operations); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java index 4321929b77..f7a2fa0830 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java @@ -1,8 +1,5 @@ package org.whispersystems.signalservice.api.storage; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.libsignal.protocol.logging.Log; import org.whispersystems.signalservice.api.payments.PaymentsConstants; import org.whispersystems.signalservice.api.push.ServiceId; @@ -12,15 +9,19 @@ import org.whispersystems.signalservice.api.util.ProtoUtil; import org.whispersystems.signalservice.internal.storage.protos.AccountRecord; import org.whispersystems.signalservice.internal.storage.protos.OptionalBool; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import javax.annotation.Nullable; +import okio.ByteString; + public final class SignalAccountRecord implements SignalRecord { private static final String TAG = SignalAccountRecord.class.getSimpleName(); @@ -43,16 +44,16 @@ public final class SignalAccountRecord implements SignalRecord { this.proto = proto; this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); - this.givenName = OptionalUtil.absentIfEmpty(proto.getGivenName()); - this.familyName = OptionalUtil.absentIfEmpty(proto.getFamilyName()); - this.profileKey = OptionalUtil.absentIfEmpty(proto.getProfileKey()); - this.avatarUrlPath = OptionalUtil.absentIfEmpty(proto.getAvatarUrlPath()); - this.pinnedConversations = new ArrayList<>(proto.getPinnedConversationsCount()); - this.payments = new Payments(proto.getPayments().getEnabled(), OptionalUtil.absentIfEmpty(proto.getPayments().getEntropy())); - this.defaultReactions = new ArrayList<>(proto.getPreferredReactionEmojiList()); - this.subscriber = new Subscriber(proto.getSubscriberCurrencyCode(), proto.getSubscriberId().toByteArray()); + this.givenName = OptionalUtil.absentIfEmpty(proto.givenName); + this.familyName = OptionalUtil.absentIfEmpty(proto.familyName); + this.profileKey = OptionalUtil.absentIfEmpty(proto.profileKey); + this.avatarUrlPath = OptionalUtil.absentIfEmpty(proto.avatarUrlPath); + this.pinnedConversations = new ArrayList<>(proto.pinnedConversations.size()); + this.payments = new Payments(proto.payments.enabled, OptionalUtil.absentIfEmpty(proto.payments.entropy)); + this.defaultReactions = new ArrayList<>(proto.preferredReactionEmoji.size()); + this.subscriber = new Subscriber(proto.subscriberCurrencyCode, proto.subscriberId.toByteArray()); - for (AccountRecord.PinnedConversation conversation : proto.getPinnedConversationsList()) { + for (AccountRecord.PinnedConversation conversation : proto.pinnedConversations) { pinnedConversations.add(PinnedConversation.fromRemote(conversation)); } } @@ -212,7 +213,7 @@ public final class SignalAccountRecord implements SignalRecord { } public byte[] serializeUnknownFields() { - return hasUnknownFields ? proto.toByteArray() : null; + return hasUnknownFields ? proto.encode() : null; } public Optional getGivenName() { @@ -232,35 +233,35 @@ public final class SignalAccountRecord implements SignalRecord { } public boolean isNoteToSelfArchived() { - return proto.getNoteToSelfArchived(); + return proto.noteToSelfArchived; } public boolean isNoteToSelfForcedUnread() { - return proto.getNoteToSelfMarkedUnread(); + return proto.noteToSelfMarkedUnread; } public boolean isReadReceiptsEnabled() { - return proto.getReadReceipts(); + return proto.readReceipts; } public boolean isTypingIndicatorsEnabled() { - return proto.getTypingIndicators(); + return proto.typingIndicators; } public boolean isSealedSenderIndicatorsEnabled() { - return proto.getSealedSenderIndicators(); + return proto.sealedSenderIndicators; } public boolean isLinkPreviewsEnabled() { - return proto.getLinkPreviews(); + return proto.linkPreviews; } public AccountRecord.PhoneNumberSharingMode getPhoneNumberSharingMode() { - return proto.getPhoneNumberSharingMode(); + return proto.phoneNumberSharingMode; } public boolean isPhoneNumberUnlisted() { - return proto.getUnlistedPhoneNumber(); + return proto.unlistedPhoneNumber; } public List getPinnedConversations() { @@ -268,7 +269,7 @@ public final class SignalAccountRecord implements SignalRecord { } public boolean isPreferContactAvatars() { - return proto.getPreferContactAvatars(); + return proto.preferContactAvatars; } public Payments getPayments() { @@ -276,15 +277,15 @@ public final class SignalAccountRecord implements SignalRecord { } public int getUniversalExpireTimer() { - return proto.getUniversalExpireTimer(); + return proto.universalExpireTimer; } public boolean isPrimarySendsSms() { - return proto.getPrimarySendsSms(); + return proto.primarySendsSms; } public String getE164() { - return proto.getE164(); + return proto.e164; } public List getDefaultReactions() { @@ -296,47 +297,47 @@ public final class SignalAccountRecord implements SignalRecord { } public boolean isDisplayBadgesOnProfile() { - return proto.getDisplayBadgesOnProfile(); + return proto.displayBadgesOnProfile; } public boolean isSubscriptionManuallyCancelled() { - return proto.getSubscriptionManuallyCancelled(); + return proto.subscriptionManuallyCancelled; } public boolean isKeepMutedChatsArchived() { - return proto.getKeepMutedChatsArchived(); + return proto.keepMutedChatsArchived; } public boolean hasSetMyStoriesPrivacy() { - return proto.getHasSetMyStoriesPrivacy(); + return proto.hasSetMyStoriesPrivacy; } public boolean hasViewedOnboardingStory() { - return proto.getHasViewedOnboardingStory(); + return proto.hasViewedOnboardingStory; } public boolean isStoriesDisabled() { - return proto.getStoriesDisabled(); + return proto.storiesDisabled; } public OptionalBool getStoryViewReceiptsState() { - return proto.getStoryViewReceiptsEnabled(); + return proto.storyViewReceiptsEnabled; } public boolean hasReadOnboardingStory() { - return proto.getHasReadOnboardingStory(); + return proto.hasReadOnboardingStory; } public boolean hasSeenGroupStoryEducationSheet() { - return proto.getHasSeenGroupStoryEducationSheet(); + return proto.hasSeenGroupStoryEducationSheet; } public @Nullable String getUsername() { - return proto.getUsername(); + return proto.username; } public @Nullable AccountRecord.UsernameLink getUsernameLink() { - return proto.getUsernameLink(); + return proto.usernameLink; } public AccountRecord toProto() { @@ -385,18 +386,18 @@ public final class SignalAccountRecord implements SignalRecord { } static PinnedConversation fromRemote(AccountRecord.PinnedConversation remote) { - if (remote.hasContact()) { - ServiceId serviceId = ServiceId.parseOrNull(remote.getContact().getServiceId()); + if (remote.contact != null) { + ServiceId serviceId = ServiceId.parseOrNull(remote.contact.serviceId); if (serviceId != null) { - return forContact(new SignalServiceAddress(serviceId, remote.getContact().getE164())); + return forContact(new SignalServiceAddress(serviceId, remote.contact.e164)); } else { - Log.w(TAG, "Bad serviceId on pinned contact! Length: " + remote.getContact().getServiceId()); + Log.w(TAG, "Bad serviceId on pinned contact! Length: " + remote.contact.serviceId); return PinnedConversation.forEmpty(); } - } else if (!remote.getLegacyGroupId().isEmpty()) { - return forGroupV1(remote.getLegacyGroupId().toByteArray()); - } else if (!remote.getGroupMasterKey().isEmpty()) { - return forGroupV2(remote.getGroupMasterKey().toByteArray()); + } else if (remote.legacyGroupId != null && remote.legacyGroupId.size() > 0) { + return forGroupV1(remote.legacyGroupId.toByteArray()); + } else if (remote.groupMasterKey != null && remote.groupMasterKey.size() > 0) { + return forGroupV2(remote.groupMasterKey.toByteArray()); } else { return PinnedConversation.forEmpty(); } @@ -420,20 +421,20 @@ public final class SignalAccountRecord implements SignalRecord { private AccountRecord.PinnedConversation toRemote() { if (contact.isPresent()) { - AccountRecord.PinnedConversation.Contact.Builder contactBuilder = AccountRecord.PinnedConversation.Contact.newBuilder(); + AccountRecord.PinnedConversation.Contact.Builder contactBuilder = new AccountRecord.PinnedConversation.Contact.Builder(); - contactBuilder.setServiceId(contact.get().getServiceId().toString()); + contactBuilder.serviceId(contact.get().getServiceId().toString()); if (contact.get().getNumber().isPresent()) { - contactBuilder.setE164(contact.get().getNumber().get()); + contactBuilder.e164(contact.get().getNumber().get()); } - return AccountRecord.PinnedConversation.newBuilder().setContact(contactBuilder.build()).build(); + return new AccountRecord.PinnedConversation.Builder().contact(contactBuilder.build()).build(); } else if (groupV1Id.isPresent()) { - return AccountRecord.PinnedConversation.newBuilder().setLegacyGroupId(ByteString.copyFrom(groupV1Id.get())).build(); + return new AccountRecord.PinnedConversation.Builder().legacyGroupId(ByteString.of(groupV1Id.get())).build(); } else if (groupV2MasterKey.isPresent()) { - return AccountRecord.PinnedConversation.newBuilder().setGroupMasterKey(ByteString.copyFrom(groupV2MasterKey.get())).build(); + return new AccountRecord.PinnedConversation.Builder().groupMasterKey(ByteString.of(groupV2MasterKey.get())).build(); } else { - return AccountRecord.PinnedConversation.newBuilder().build(); + return new AccountRecord.PinnedConversation.Builder().build(); } } @@ -538,184 +539,178 @@ public final class SignalAccountRecord implements SignalRecord { if (serializedUnknowns != null) { this.builder = parseUnknowns(serializedUnknowns); } else { - this.builder = AccountRecord.newBuilder(); + this.builder = new AccountRecord.Builder(); } } public Builder setGivenName(String givenName) { - builder.setGivenName(givenName == null ? "" : givenName); + builder.givenName(givenName == null ? "" : givenName); return this; } public Builder setFamilyName(String familyName) { - builder.setFamilyName(familyName == null ? "" : familyName); + builder.familyName(familyName == null ? "" : familyName); return this; } public Builder setProfileKey(byte[] profileKey) { - builder.setProfileKey(profileKey == null ? ByteString.EMPTY : ByteString.copyFrom(profileKey)); + builder.profileKey(profileKey == null ? ByteString.EMPTY : ByteString.of(profileKey)); return this; } public Builder setAvatarUrlPath(String urlPath) { - builder.setAvatarUrlPath(urlPath == null ? "" : urlPath); + builder.avatarUrlPath(urlPath == null ? "" : urlPath); return this; } public Builder setNoteToSelfArchived(boolean archived) { - builder.setNoteToSelfArchived(archived); + builder.noteToSelfArchived(archived); return this; } public Builder setNoteToSelfForcedUnread(boolean forcedUnread) { - builder.setNoteToSelfMarkedUnread(forcedUnread); + builder.noteToSelfMarkedUnread(forcedUnread); return this; } public Builder setReadReceiptsEnabled(boolean enabled) { - builder.setReadReceipts(enabled); + builder.readReceipts(enabled); return this; } public Builder setTypingIndicatorsEnabled(boolean enabled) { - builder.setTypingIndicators(enabled); + builder.typingIndicators(enabled); return this; } public Builder setSealedSenderIndicatorsEnabled(boolean enabled) { - builder.setSealedSenderIndicators(enabled); + builder.sealedSenderIndicators(enabled); return this; } public Builder setLinkPreviewsEnabled(boolean enabled) { - builder.setLinkPreviews(enabled); + builder.linkPreviews(enabled); return this; } public Builder setPhoneNumberSharingMode(AccountRecord.PhoneNumberSharingMode mode) { - builder.setPhoneNumberSharingMode(mode); + builder.phoneNumberSharingMode(mode); return this; } public Builder setUnlistedPhoneNumber(boolean unlisted) { - builder.setUnlistedPhoneNumber(unlisted); + builder.unlistedPhoneNumber(unlisted); return this; } public Builder setPinnedConversations(List pinnedConversations) { - builder.clearPinnedConversations(); - - for (PinnedConversation pinned : pinnedConversations) { - builder.addPinnedConversations(pinned.toRemote()); - } - + builder.pinnedConversations(pinnedConversations.stream().map(PinnedConversation::toRemote).collect(Collectors.toList())); return this; } public Builder setPreferContactAvatars(boolean preferContactAvatars) { - builder.setPreferContactAvatars(preferContactAvatars); + builder.preferContactAvatars(preferContactAvatars); return this; } public Builder setPayments(boolean enabled, byte[] entropy) { - org.whispersystems.signalservice.internal.storage.protos.Payments.Builder paymentsBuilder = org.whispersystems.signalservice.internal.storage.protos.Payments.newBuilder(); + org.whispersystems.signalservice.internal.storage.protos.Payments.Builder paymentsBuilder = new org.whispersystems.signalservice.internal.storage.protos.Payments.Builder(); boolean entropyPresent = entropy != null && entropy.length == PaymentsConstants.PAYMENTS_ENTROPY_LENGTH; - paymentsBuilder.setEnabled(enabled && entropyPresent); + paymentsBuilder.enabled(enabled && entropyPresent); if (entropyPresent) { - paymentsBuilder.setEntropy(ByteString.copyFrom(entropy)); + paymentsBuilder.entropy(ByteString.of(entropy)); } - builder.setPayments(paymentsBuilder); + builder.payments(paymentsBuilder.build()); return this; } public Builder setUniversalExpireTimer(int timer) { - builder.setUniversalExpireTimer(timer); + builder.universalExpireTimer(timer); return this; } public Builder setPrimarySendsSms(boolean primarySendsSms) { - builder.setPrimarySendsSms(primarySendsSms); + builder.primarySendsSms(primarySendsSms); return this; } public Builder setE164(String e164) { - builder.setE164(e164); + builder.e164(e164); return this; } public Builder setDefaultReactions(List defaultReactions) { - builder.clearPreferredReactionEmoji(); - builder.addAllPreferredReactionEmoji(defaultReactions); + builder.preferredReactionEmoji(new ArrayList<>(defaultReactions)); return this; } public Builder setSubscriber(Subscriber subscriber) { if (subscriber.id.isPresent() && subscriber.currencyCode.isPresent()) { - builder.setSubscriberId(ByteString.copyFrom(subscriber.id.get())); - builder.setSubscriberCurrencyCode(subscriber.currencyCode.get()); + builder.subscriberId(ByteString.of(subscriber.id.get())); + builder.subscriberCurrencyCode(subscriber.currencyCode.get()); } else { - builder.clearSubscriberId(); - builder.clearSubscriberCurrencyCode(); + builder.subscriberId(StorageRecordProtoUtil.getDefaultAccountRecord().subscriberId); + builder.subscriberCurrencyCode(StorageRecordProtoUtil.getDefaultAccountRecord().subscriberCurrencyCode); } return this; } public Builder setDisplayBadgesOnProfile(boolean displayBadgesOnProfile) { - builder.setDisplayBadgesOnProfile(displayBadgesOnProfile); + builder.displayBadgesOnProfile(displayBadgesOnProfile); return this; } public Builder setSubscriptionManuallyCancelled(boolean subscriptionManuallyCancelled) { - builder.setSubscriptionManuallyCancelled(subscriptionManuallyCancelled); + builder.subscriptionManuallyCancelled(subscriptionManuallyCancelled); return this; } public Builder setKeepMutedChatsArchived(boolean keepMutedChatsArchived) { - builder.setKeepMutedChatsArchived(keepMutedChatsArchived); + builder.keepMutedChatsArchived(keepMutedChatsArchived); return this; } public Builder setHasSetMyStoriesPrivacy(boolean hasSetMyStoriesPrivacy) { - builder.setHasSetMyStoriesPrivacy(hasSetMyStoriesPrivacy); + builder.hasSetMyStoriesPrivacy(hasSetMyStoriesPrivacy); return this; } public Builder setHasViewedOnboardingStory(boolean hasViewedOnboardingStory) { - builder.setHasViewedOnboardingStory(hasViewedOnboardingStory); + builder.hasViewedOnboardingStory(hasViewedOnboardingStory); return this; } public Builder setStoriesDisabled(boolean storiesDisabled) { - builder.setStoriesDisabled(storiesDisabled); + builder.storiesDisabled(storiesDisabled); return this; } public Builder setStoryViewReceiptsState(OptionalBool storyViewedReceiptsEnabled) { - builder.setStoryViewReceiptsEnabled(storyViewedReceiptsEnabled); + builder.storyViewReceiptsEnabled(storyViewedReceiptsEnabled); return this; } public Builder setHasReadOnboardingStory(boolean hasReadOnboardingStory) { - builder.setHasReadOnboardingStory(hasReadOnboardingStory); + builder.hasReadOnboardingStory(hasReadOnboardingStory); return this; } public Builder setHasSeenGroupStoryEducationSheet(boolean hasSeenGroupStoryEducationSheet) { - builder.setHasSeenGroupStoryEducationSheet(hasSeenGroupStoryEducationSheet); + builder.hasSeenGroupStoryEducationSheet(hasSeenGroupStoryEducationSheet); return this; } public Builder setUsername(@Nullable String username) { if (username == null || username.isEmpty()) { - builder.clearUsername(); + builder.username(StorageRecordProtoUtil.getDefaultAccountRecord().username); } else { - builder.setUsername(username); + builder.username(username); } return this; @@ -723,9 +718,9 @@ public final class SignalAccountRecord implements SignalRecord { public Builder setUsernameLink(@Nullable AccountRecord.UsernameLink link) { if (link == null) { - builder.clearUsernameLink(); + builder.usernameLink(StorageRecordProtoUtil.getDefaultAccountRecord().usernameLink); } else { - builder.setUsernameLink(link); + builder.usernameLink(link); } return this; @@ -733,10 +728,10 @@ public final class SignalAccountRecord implements SignalRecord { private static AccountRecord.Builder parseUnknowns(byte[] serializedUnknowns) { try { - return AccountRecord.parseFrom(serializedUnknowns).toBuilder(); - } catch (InvalidProtocolBufferException e) { + return AccountRecord.ADAPTER.decode(serializedUnknowns).newBuilder(); + } catch (IOException e) { Log.w(TAG, "Failed to combine unknown fields!", e); - return AccountRecord.newBuilder(); + return new AccountRecord.Builder(); } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalContactRecord.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalContactRecord.java index 120553bbc4..e753f19034 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalContactRecord.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalContactRecord.java @@ -1,23 +1,23 @@ package org.whispersystems.signalservice.api.storage; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.libsignal.protocol.logging.Log; +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.OptionalUtil; import org.whispersystems.signalservice.api.util.ProtoUtil; import org.whispersystems.signalservice.internal.storage.protos.ContactRecord; import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState; +import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Optional; +import okio.ByteString; + public final class SignalContactRecord implements SignalRecord { private static final String TAG = SignalContactRecord.class.getSimpleName(); @@ -42,17 +42,17 @@ public final class SignalContactRecord implements SignalRecord { this.id = id; this.proto = proto; this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); - this.aci = OptionalUtil.absentIfEmpty(proto.getAci()).map(ACI::parseOrNull).map(it -> it.isUnknown() ? null : it); - this.pni = OptionalUtil.absentIfEmpty(proto.getPni()).map(PNI::parseOrNull).map(it -> it.isUnknown() ? null : it); - this.e164 = OptionalUtil.absentIfEmpty(proto.getE164()); - this.profileGivenName = OptionalUtil.absentIfEmpty(proto.getGivenName()); - this.profileFamilyName = OptionalUtil.absentIfEmpty(proto.getFamilyName()); - this.systemGivenName = OptionalUtil.absentIfEmpty(proto.getSystemGivenName()); - this.systemFamilyName = OptionalUtil.absentIfEmpty(proto.getSystemFamilyName()); - this.systemNickname = OptionalUtil.absentIfEmpty(proto.getSystemNickname()); - this.profileKey = OptionalUtil.absentIfEmpty(proto.getProfileKey()); - this.username = OptionalUtil.absentIfEmpty(proto.getUsername()); - this.identityKey = OptionalUtil.absentIfEmpty(proto.getIdentityKey()); + this.aci = OptionalUtil.absentIfEmpty(proto.aci).map(ACI::parseOrNull).map(it -> it.isUnknown() ? null : it); + this.pni = OptionalUtil.absentIfEmpty(proto.pni).map(PNI::parseOrNull).map(it -> it.isUnknown() ? null : it); + this.e164 = OptionalUtil.absentIfEmpty(proto.e164); + this.profileGivenName = OptionalUtil.absentIfEmpty(proto.givenName); + this.profileFamilyName = OptionalUtil.absentIfEmpty(proto.familyName); + this.systemGivenName = OptionalUtil.absentIfEmpty(proto.systemGivenName); + this.systemFamilyName = OptionalUtil.absentIfEmpty(proto.systemFamilyName); + this.systemNickname = OptionalUtil.absentIfEmpty(proto.systemNickname); + this.profileKey = OptionalUtil.absentIfEmpty(proto.profileKey); + this.username = OptionalUtil.absentIfEmpty(proto.username); + this.identityKey = OptionalUtil.absentIfEmpty(proto.identityKey); } @Override @@ -170,7 +170,7 @@ public final class SignalContactRecord implements SignalRecord { } public byte[] serializeUnknownFields() { - return hasUnknownFields ? proto.toByteArray() : null; + return hasUnknownFields ? proto.encode() : null; } public Optional getAci() { @@ -228,46 +228,46 @@ public final class SignalContactRecord implements SignalRecord { } public IdentityState getIdentityState() { - return proto.getIdentityState(); + return proto.identityState; } public boolean isBlocked() { - return proto.getBlocked(); + return proto.blocked; } public boolean isProfileSharingEnabled() { - return proto.getWhitelisted(); + return proto.whitelisted; } public boolean isArchived() { - return proto.getArchived(); + return proto.archived; } public boolean isForcedUnread() { - return proto.getMarkedUnread(); + return proto.markedUnread; } public long getMuteUntil() { - return proto.getMutedUntilTimestamp(); + return proto.mutedUntilTimestamp; } public boolean shouldHideStory() { - return proto.getHideStory(); + return proto.hideStory; } public long getUnregisteredTimestamp() { - return proto.getUnregisteredAtTimestamp(); + return proto.unregisteredAtTimestamp; } public boolean isHidden() { - return proto.getHidden(); + return proto.hidden; } /** * Returns the same record, but stripped of the PNI field. Only used while PNP is in development. */ public SignalContactRecord withoutPni() { - return new SignalContactRecord(id, proto.toBuilder().clearPni().build()); + return new SignalContactRecord(id, proto.newBuilder().pni("").build()); } public ContactRecord toProto() { @@ -298,113 +298,113 @@ public final class SignalContactRecord implements SignalRecord { if (serializedUnknowns != null) { this.builder = parseUnknowns(serializedUnknowns); } else { - this.builder = ContactRecord.newBuilder(); + this.builder = new ContactRecord.Builder(); } - builder.setAci(aci.toString()); + builder.aci(aci.toString()); } public Builder setE164(String e164) { - builder.setE164(e164 == null ? "" : e164); + builder.e164(e164 == null ? "" : e164); return this; } public Builder setPni(PNI pni) { - builder.setPni(pni == null ? "" : pni.toStringWithoutPrefix()); + builder.pni(pni == null ? "" : pni.toStringWithoutPrefix()); return this; } public Builder setProfileGivenName(String givenName) { - builder.setGivenName(givenName == null ? "" : givenName); + builder.givenName(givenName == null ? "" : givenName); return this; } public Builder setProfileFamilyName(String familyName) { - builder.setFamilyName(familyName == null ? "" : familyName); + builder.familyName(familyName == null ? "" : familyName); return this; } public Builder setSystemGivenName(String givenName) { - builder.setSystemGivenName(givenName == null ? "" : givenName); + builder.systemGivenName(givenName == null ? "" : givenName); return this; } public Builder setSystemFamilyName(String familyName) { - builder.setSystemFamilyName(familyName == null ? "" : familyName); + builder.systemFamilyName(familyName == null ? "" : familyName); return this; } public Builder setSystemNickname(String nickname) { - builder.setSystemNickname(nickname == null ? "" : nickname); + builder.systemNickname(nickname == null ? "" : nickname); return this; } public Builder setProfileKey(byte[] profileKey) { - builder.setProfileKey(profileKey == null ? ByteString.EMPTY : ByteString.copyFrom(profileKey)); + builder.profileKey(profileKey == null ? ByteString.EMPTY : ByteString.of(profileKey)); return this; } public Builder setUsername(String username) { - builder.setUsername(username == null ? "" : username); + builder.username(username == null ? "" : username); return this; } public Builder setIdentityKey(byte[] identityKey) { - builder.setIdentityKey(identityKey == null ? ByteString.EMPTY : ByteString.copyFrom(identityKey)); + builder.identityKey(identityKey == null ? ByteString.EMPTY : ByteString.of(identityKey)); return this; } public Builder setIdentityState(IdentityState identityState) { - builder.setIdentityState(identityState == null ? IdentityState.DEFAULT : identityState); + builder.identityState(identityState == null ? IdentityState.DEFAULT : identityState); return this; } public Builder setBlocked(boolean blocked) { - builder.setBlocked(blocked); + builder.blocked(blocked); return this; } public Builder setProfileSharingEnabled(boolean profileSharingEnabled) { - builder.setWhitelisted(profileSharingEnabled); + builder.whitelisted(profileSharingEnabled); return this; } public Builder setArchived(boolean archived) { - builder.setArchived(archived); + builder.archived(archived); return this; } public Builder setForcedUnread(boolean forcedUnread) { - builder.setMarkedUnread(forcedUnread); + builder.markedUnread(forcedUnread); return this; } public Builder setMuteUntil(long muteUntil) { - builder.setMutedUntilTimestamp(muteUntil); + builder.mutedUntilTimestamp(muteUntil); return this; } public Builder setHideStory(boolean hideStory) { - builder.setHideStory(hideStory); + builder.hideStory(hideStory); return this; } public Builder setUnregisteredTimestamp(long timestamp) { - builder.setUnregisteredAtTimestamp(timestamp); + builder.unregisteredAtTimestamp(timestamp); return this; } public Builder setHidden(boolean hidden) { - builder.setHidden(hidden); + builder.hidden(hidden); return this; } private static ContactRecord.Builder parseUnknowns(byte[] serializedUnknowns) { try { - return ContactRecord.parseFrom(serializedUnknowns).toBuilder(); - } catch (InvalidProtocolBufferException e) { + return ContactRecord.ADAPTER.decode(serializedUnknowns).newBuilder(); + } catch (IOException e) { Log.w(TAG, "Failed to combine unknown fields!", e); - return ContactRecord.newBuilder(); + return new ContactRecord.Builder(); } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV1Record.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV1Record.java index a1e4fb01ba..7df3282371 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV1Record.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV1Record.java @@ -1,17 +1,17 @@ package org.whispersystems.signalservice.api.storage; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.libsignal.protocol.logging.Log; import org.whispersystems.signalservice.api.util.ProtoUtil; import org.whispersystems.signalservice.internal.storage.protos.GroupV1Record; +import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import okio.ByteString; + public final class SignalGroupV1Record implements SignalRecord { private static final String TAG = SignalGroupV1Record.class.getSimpleName(); @@ -24,7 +24,7 @@ public final class SignalGroupV1Record implements SignalRecord { public SignalGroupV1Record(StorageId id, GroupV1Record proto) { this.id = id; this.proto = proto; - this.groupId = proto.getId().toByteArray(); + this.groupId = proto.id.toByteArray(); this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); } @@ -87,7 +87,7 @@ public final class SignalGroupV1Record implements SignalRecord { } public byte[] serializeUnknownFields() { - return hasUnknownFields ? proto.toByteArray() : null; + return hasUnknownFields ? proto.encode() : null; } public byte[] getGroupId() { @@ -95,23 +95,23 @@ public final class SignalGroupV1Record implements SignalRecord { } public boolean isBlocked() { - return proto.getBlocked(); + return proto.blocked; } public boolean isProfileSharingEnabled() { - return proto.getWhitelisted(); + return proto.whitelisted; } public boolean isArchived() { - return proto.getArchived(); + return proto.archived; } public boolean isForcedUnread() { - return proto.getMarkedUnread(); + return proto.markedUnread; } public long getMuteUntil() { - return proto.getMutedUntilTimestamp(); + return proto.mutedUntilTimestamp; } public GroupV1Record toProto() { @@ -142,43 +142,43 @@ public final class SignalGroupV1Record implements SignalRecord { if (serializedUnknowns != null) { this.builder = parseUnknowns(serializedUnknowns); } else { - this.builder = GroupV1Record.newBuilder(); + this.builder = new GroupV1Record.Builder(); } - builder.setId(ByteString.copyFrom(groupId)); + builder.id(ByteString.of(groupId)); } public Builder setBlocked(boolean blocked) { - builder.setBlocked(blocked); + builder.blocked(blocked); return this; } public Builder setProfileSharingEnabled(boolean profileSharingEnabled) { - builder.setWhitelisted(profileSharingEnabled); + builder.whitelisted(profileSharingEnabled); return this; } public Builder setArchived(boolean archived) { - builder.setArchived(archived); + builder.archived(archived); return this; } public Builder setForcedUnread(boolean forcedUnread) { - builder.setMarkedUnread(forcedUnread); + builder.markedUnread(forcedUnread); return this; } public Builder setMuteUntil(long muteUntil) { - builder.setMutedUntilTimestamp(muteUntil); + builder.mutedUntilTimestamp(muteUntil); return this; } private static GroupV1Record.Builder parseUnknowns(byte[] serializedUnknowns) { try { - return GroupV1Record.parseFrom(serializedUnknowns).toBuilder(); - } catch (InvalidProtocolBufferException e) { + return GroupV1Record.ADAPTER.decode(serializedUnknowns).newBuilder(); + } catch (IOException e) { Log.w(TAG, "Failed to combine unknown fields!", e); - return GroupV1Record.newBuilder(); + return new GroupV1Record.Builder(); } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV2Record.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV2Record.java index 9e057b7e11..4ef3cc874f 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV2Record.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV2Record.java @@ -1,19 +1,19 @@ package org.whispersystems.signalservice.api.storage; -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.groups.GroupMasterKey; import org.whispersystems.signalservice.api.util.ProtoUtil; import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record; +import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import okio.ByteString; + public final class SignalGroupV2Record implements SignalRecord { private static final String TAG = SignalGroupV2Record.class.getSimpleName(); @@ -27,7 +27,7 @@ public final class SignalGroupV2Record implements SignalRecord { this.id = id; this.proto = proto; this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); - this.masterKey = proto.getMasterKey().toByteArray(); + this.masterKey = proto.masterKey.toByteArray(); } @Override @@ -101,7 +101,7 @@ public final class SignalGroupV2Record implements SignalRecord { } public byte[] serializeUnknownFields() { - return hasUnknownFields ? proto.toByteArray() : null; + return hasUnknownFields ? proto.encode() : null; } public byte[] getMasterKeyBytes() { @@ -117,35 +117,35 @@ public final class SignalGroupV2Record implements SignalRecord { } public boolean isBlocked() { - return proto.getBlocked(); + return proto.blocked; } public boolean isProfileSharingEnabled() { - return proto.getWhitelisted(); + return proto.whitelisted; } public boolean isArchived() { - return proto.getArchived(); + return proto.archived; } public boolean isForcedUnread() { - return proto.getMarkedUnread(); + return proto.markedUnread; } public long getMuteUntil() { - return proto.getMutedUntilTimestamp(); + return proto.mutedUntilTimestamp; } public boolean notifyForMentionsWhenMuted() { - return !proto.getDontNotifyForMentionsIfMuted(); + return !proto.dontNotifyForMentionsIfMuted; } public boolean shouldHideStory() { - return proto.getHideStory(); + return proto.hideStory; } public GroupV2Record.StorySendMode getStorySendMode() { - return proto.getStorySendMode(); + return proto.storySendMode; } public GroupV2Record toProto() { @@ -180,58 +180,58 @@ public final class SignalGroupV2Record implements SignalRecord { if (serializedUnknowns != null) { this.builder = parseUnknowns(serializedUnknowns); } else { - this.builder = GroupV2Record.newBuilder(); + this.builder = new GroupV2Record.Builder(); } - builder.setMasterKey(ByteString.copyFrom(masterKey)); + builder.masterKey(ByteString.of(masterKey)); } public Builder setBlocked(boolean blocked) { - builder.setBlocked(blocked); + builder.blocked(blocked); return this; } public Builder setProfileSharingEnabled(boolean profileSharingEnabled) { - builder.setWhitelisted(profileSharingEnabled); + builder.whitelisted(profileSharingEnabled); return this; } public Builder setArchived(boolean archived) { - builder.setArchived(archived); + builder.archived(archived); return this; } public Builder setForcedUnread(boolean forcedUnread) { - builder.setMarkedUnread(forcedUnread); + builder.markedUnread(forcedUnread); return this; } public Builder setMuteUntil(long muteUntil) { - builder.setMutedUntilTimestamp(muteUntil); + builder.mutedUntilTimestamp(muteUntil); return this; } public Builder setNotifyForMentionsWhenMuted(boolean value) { - builder.setDontNotifyForMentionsIfMuted(!value); + builder.dontNotifyForMentionsIfMuted(!value); return this; } public Builder setHideStory(boolean hideStory) { - builder.setHideStory(hideStory); + builder.hideStory(hideStory); return this; } public Builder setStorySendMode(GroupV2Record.StorySendMode storySendMode) { - builder.setStorySendMode(storySendMode); + builder.storySendMode(storySendMode); return this; } private static GroupV2Record.Builder parseUnknowns(byte[] serializedUnknowns) { try { - return GroupV2Record.parseFrom(serializedUnknowns).toBuilder(); - } catch (InvalidProtocolBufferException e) { + return GroupV2Record.ADAPTER.decode(serializedUnknowns).newBuilder(); + } catch (IOException e) { Log.w(TAG, "Failed to combine unknown fields!", e); - return GroupV2Record.newBuilder(); + return new GroupV2Record.Builder(); } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageManifest.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageManifest.java index 95aedd011d..bfbae4731a 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageManifest.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageManifest.java @@ -1,11 +1,9 @@ package org.whispersystems.signalservice.api.storage; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord; import org.whispersystems.signalservice.internal.storage.protos.StorageManifest; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -13,6 +11,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import okio.ByteString; + public class SignalStorageManifest { public static final SignalStorageManifest EMPTY = new SignalStorageManifest(0, 1, Collections.emptyList()); @@ -39,16 +39,16 @@ public class SignalStorageManifest { public static SignalStorageManifest deserialize(byte[] serialized) { try { - StorageManifest manifest = StorageManifest.parseFrom(serialized); - ManifestRecord manifestRecord = ManifestRecord.parseFrom(manifest.getValue()); - List ids = new ArrayList<>(manifestRecord.getIdentifiersCount()); + StorageManifest manifest = StorageManifest.ADAPTER.decode(serialized); + ManifestRecord manifestRecord = ManifestRecord.ADAPTER.decode(manifest.value_); + List ids = new ArrayList<>(manifestRecord.identifiers.size()); - for (ManifestRecord.Identifier id : manifestRecord.getIdentifiersList()) { - ids.add(StorageId.forType(id.getRaw().toByteArray(), id.getTypeValue())); + for (ManifestRecord.Identifier id : manifestRecord.identifiers) { + ids.add(StorageId.forType(id.raw.toByteArray(), id.type.getValue())); } - return new SignalStorageManifest(manifest.getVersion(), manifestRecord.getSourceDevice(), ids); - } catch (InvalidProtocolBufferException e) { + return new SignalStorageManifest(manifest.version, manifestRecord.sourceDevice, ids); + } catch (IOException e) { throw new AssertionError(e); } } @@ -70,7 +70,7 @@ public class SignalStorageManifest { } public Optional getAccountStorageId() { - List list = storageIdsByType.get(ManifestRecord.Identifier.Type.ACCOUNT_VALUE); + List list = storageIdsByType.get(ManifestRecord.Identifier.Type.ACCOUNT.getValue()); if (list != null && list.size() > 0) { return Optional.of(list.get(0)); @@ -87,21 +87,21 @@ public class SignalStorageManifest { List ids = new ArrayList<>(storageIds.size()); for (StorageId id : storageIds) { - ids.add(ManifestRecord.Identifier.newBuilder() - .setTypeValue(id.getType()) - .setRaw(ByteString.copyFrom(id.getRaw())) - .build()); + ids.add(new ManifestRecord.Identifier.Builder() + .type(ManifestRecord.Identifier.Type.Companion.fromValue(id.getType())) + .raw(ByteString.of(id.getRaw())) + .build()); } - ManifestRecord manifestRecord = ManifestRecord.newBuilder() - .addAllIdentifiers(ids) - .setSourceDevice(sourceDeviceId) - .build(); + ManifestRecord manifestRecord = new ManifestRecord.Builder() + .identifiers(ids) + .sourceDevice(sourceDeviceId) + .build(); - return StorageManifest.newBuilder() - .setVersion(version) - .setValue(manifestRecord.toByteString()) - .build() - .toByteArray(); + return new StorageManifest.Builder() + .version(version) + .value_(manifestRecord.encodeByteString()) + .build() + .encode(); } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageModels.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageModels.java index 212586a966..80dceb5a93 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageModels.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageModels.java @@ -1,7 +1,5 @@ package org.whispersystems.signalservice.api.storage; -import com.google.protobuf.ByteString; - import org.signal.libsignal.protocol.InvalidKeyException; import org.signal.libsignal.protocol.logging.Log; import org.signal.libsignal.zkgroup.groups.GroupMasterKey; @@ -14,38 +12,40 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import okio.ByteString; + public final class SignalStorageModels { private static final String TAG = SignalStorageModels.class.getSimpleName(); public static SignalStorageManifest remoteToLocalStorageManifest(StorageManifest manifest, StorageKey storageKey) throws IOException, InvalidKeyException { - byte[] rawRecord = SignalStorageCipher.decrypt(storageKey.deriveManifestKey(manifest.getVersion()), manifest.getValue().toByteArray()); - ManifestRecord manifestRecord = ManifestRecord.parseFrom(rawRecord); - List ids = new ArrayList<>(manifestRecord.getIdentifiersCount()); + byte[] rawRecord = SignalStorageCipher.decrypt(storageKey.deriveManifestKey(manifest.version), manifest.value_.toByteArray()); + ManifestRecord manifestRecord = ManifestRecord.ADAPTER.decode(rawRecord); + List ids = new ArrayList<>(manifestRecord.identifiers.size()); - for (ManifestRecord.Identifier id : manifestRecord.getIdentifiersList()) { - ids.add(StorageId.forType(id.getRaw().toByteArray(), id.getTypeValue())); + for (ManifestRecord.Identifier id : manifestRecord.identifiers) { + ids.add(StorageId.forType(id.raw.toByteArray(), id.type.getValue())); } - return new SignalStorageManifest(manifestRecord.getVersion(), manifestRecord.getSourceDevice(), ids); + return new SignalStorageManifest(manifestRecord.version, manifestRecord.sourceDevice, ids); } public static SignalStorageRecord remoteToLocalStorageRecord(StorageItem item, int type, StorageKey storageKey) throws IOException, InvalidKeyException { - byte[] key = item.getKey().toByteArray(); - byte[] rawRecord = SignalStorageCipher.decrypt(storageKey.deriveItemKey(key), item.getValue().toByteArray()); - StorageRecord record = StorageRecord.parseFrom(rawRecord); + byte[] key = item.key.toByteArray(); + byte[] rawRecord = SignalStorageCipher.decrypt(storageKey.deriveItemKey(key), item.value_.toByteArray()); + StorageRecord record = StorageRecord.ADAPTER.decode(rawRecord); StorageId id = StorageId.forType(key, type); - if (record.hasContact() && type == ManifestRecord.Identifier.Type.CONTACT_VALUE) { - return SignalStorageRecord.forContact(id, new SignalContactRecord(id, record.getContact())); - } else if (record.hasGroupV1() && type == ManifestRecord.Identifier.Type.GROUPV1_VALUE) { - return SignalStorageRecord.forGroupV1(id, new SignalGroupV1Record(id, record.getGroupV1())); - } else if (record.hasGroupV2() && type == ManifestRecord.Identifier.Type.GROUPV2_VALUE && record.getGroupV2().getMasterKey().size() == GroupMasterKey.SIZE) { - return SignalStorageRecord.forGroupV2(id, new SignalGroupV2Record(id, record.getGroupV2())); - } else if (record.hasAccount() && type == ManifestRecord.Identifier.Type.ACCOUNT_VALUE) { - return SignalStorageRecord.forAccount(id, new SignalAccountRecord(id, record.getAccount())); - } else if (record.hasStoryDistributionList() && type == ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST_VALUE) { - return SignalStorageRecord.forStoryDistributionList(id, new SignalStoryDistributionListRecord(id, record.getStoryDistributionList())); + if (record.contact != null && type == ManifestRecord.Identifier.Type.CONTACT.getValue()) { + return SignalStorageRecord.forContact(id, new SignalContactRecord(id, record.contact)); + } else if (record.groupV1 != null && type == ManifestRecord.Identifier.Type.GROUPV1.getValue()) { + return SignalStorageRecord.forGroupV1(id, new SignalGroupV1Record(id, record.groupV1)); + } else if (record.groupV2 != null && type == ManifestRecord.Identifier.Type.GROUPV2.getValue() && record.groupV2.masterKey.size() == GroupMasterKey.SIZE) { + return SignalStorageRecord.forGroupV2(id, new SignalGroupV2Record(id, record.groupV2)); + } else if (record.account != null && type == ManifestRecord.Identifier.Type.ACCOUNT.getValue()) { + return SignalStorageRecord.forAccount(id, new SignalAccountRecord(id, record.account)); + } else if (record.storyDistributionList != null && type == ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST.getValue()) { + return SignalStorageRecord.forStoryDistributionList(id, new SignalStoryDistributionListRecord(id, record.storyDistributionList)); } else { if (StorageId.isKnownType(type)) { Log.w(TAG, "StorageId is of known type (" + type + "), but the data is bad! Falling back to unknown."); @@ -55,30 +55,30 @@ public final class SignalStorageModels { } public static StorageItem localToRemoteStorageRecord(SignalStorageRecord record, StorageKey storageKey) { - StorageRecord.Builder builder = StorageRecord.newBuilder(); + StorageRecord.Builder builder = new StorageRecord.Builder(); if (record.getContact().isPresent()) { - builder.setContact(record.getContact().get().toProto()); + builder.contact(record.getContact().get().toProto()); } else if (record.getGroupV1().isPresent()) { - builder.setGroupV1(record.getGroupV1().get().toProto()); + builder.groupV1(record.getGroupV1().get().toProto()); } else if (record.getGroupV2().isPresent()) { - builder.setGroupV2(record.getGroupV2().get().toProto()); + builder.groupV2(record.getGroupV2().get().toProto()); } else if (record.getAccount().isPresent()) { - builder.setAccount(record.getAccount().get().toProto()); + builder.account(record.getAccount().get().toProto()); } else if (record.getStoryDistributionList().isPresent()) { - builder.setStoryDistributionList(record.getStoryDistributionList().get().toProto()); + builder.storyDistributionList(record.getStoryDistributionList().get().toProto()); } else { throw new InvalidStorageWriteError(); } StorageRecord remoteRecord = builder.build(); StorageItemKey itemKey = storageKey.deriveItemKey(record.getId().getRaw()); - byte[] encryptedRecord = SignalStorageCipher.encrypt(itemKey, remoteRecord.toByteArray()); + byte[] encryptedRecord = SignalStorageCipher.encrypt(itemKey, remoteRecord.encode()); - return StorageItem.newBuilder() - .setKey(ByteString.copyFrom(record.getId().getRaw())) - .setValue(ByteString.copyFrom(encryptedRecord)) - .build(); + return new StorageItem.Builder() + .key(ByteString.of(record.getId().getRaw())) + .value_(ByteString.of(encryptedRecord)) + .build(); } private static class InvalidStorageWriteError extends Error { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStoryDistributionListRecord.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStoryDistributionListRecord.java index 986d822e84..4e2f209e3a 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStoryDistributionListRecord.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStoryDistributionListRecord.java @@ -1,20 +1,20 @@ package org.whispersystems.signalservice.api.storage; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - import org.signal.libsignal.protocol.logging.Log; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.ProtoUtil; import org.whispersystems.signalservice.internal.storage.protos.StoryDistributionListRecord; +import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import okio.ByteString; + public class SignalStoryDistributionListRecord implements SignalRecord { private static final String TAG = SignalStoryDistributionListRecord.class.getSimpleName(); @@ -28,7 +28,7 @@ public class SignalStoryDistributionListRecord implements SignalRecord { this.id = id; this.proto = proto; this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); - this.recipients = proto.getRecipientServiceIdsList() + this.recipients = proto.recipientServiceIds .stream() .map(ServiceId::parseOrNull) .filter(Objects::nonNull) @@ -51,15 +51,15 @@ public class SignalStoryDistributionListRecord implements SignalRecord { } public byte[] serializeUnknownFields() { - return hasUnknownFields ? proto.toByteArray() : null; + return hasUnknownFields ? proto.encode() : null; } public byte[] getIdentifier() { - return proto.getIdentifier().toByteArray(); + return proto.identifier.toByteArray(); } public String getName() { - return proto.getName(); + return proto.name; } public List getRecipients() { @@ -67,15 +67,15 @@ public class SignalStoryDistributionListRecord implements SignalRecord { } public long getDeletedAtTimestamp() { - return proto.getDeletedAtTimestamp(); + return proto.deletedAtTimestamp; } public boolean allowsReplies() { - return proto.getAllowsReplies(); + return proto.allowsReplies; } public boolean isBlockList() { - return proto.getIsBlockList(); + return proto.isBlockList; } @Override @@ -142,40 +142,39 @@ public class SignalStoryDistributionListRecord implements SignalRecord { if (serializedUnknowns != null) { this.builder = parseUnknowns(serializedUnknowns); } else { - this.builder = StoryDistributionListRecord.newBuilder(); + this.builder = new StoryDistributionListRecord.Builder(); } } public Builder setIdentifier(byte[] identifier) { - builder.setIdentifier(ByteString.copyFrom(identifier)); + builder.identifier(ByteString.of(identifier)); return this; } public Builder setName(String name) { - builder.setName(name); + builder.name(name); return this; } public Builder setRecipients(List recipients) { - builder.clearRecipientServiceIds(); - builder.addAllRecipientServiceIds(recipients.stream() - .map(SignalServiceAddress::getIdentifier) - .collect(Collectors.toList())); + builder.recipientServiceIds = recipients.stream() + .map(SignalServiceAddress::getIdentifier) + .collect(Collectors.toList()); return this; } public Builder setDeletedAtTimestamp(long deletedAtTimestamp) { - builder.setDeletedAtTimestamp(deletedAtTimestamp); + builder.deletedAtTimestamp(deletedAtTimestamp); return this; } public Builder setAllowsReplies(boolean allowsReplies) { - builder.setAllowsReplies(allowsReplies); + builder.allowsReplies(allowsReplies); return this; } public Builder setIsBlockList(boolean isBlockList) { - builder.setIsBlockList(isBlockList); + builder.isBlockList(isBlockList); return this; } @@ -185,10 +184,10 @@ public class SignalStoryDistributionListRecord implements SignalRecord { private static StoryDistributionListRecord.Builder parseUnknowns(byte[] serializedUnknowns) { try { - return StoryDistributionListRecord.parseFrom(serializedUnknowns).toBuilder(); - } catch (InvalidProtocolBufferException e) { + return StoryDistributionListRecord.ADAPTER.decode(serializedUnknowns).newBuilder(); + } catch (IOException e) { Log.w(TAG, "Failed to combine unknown fields!", e); - return StoryDistributionListRecord.newBuilder(); + return new StoryDistributionListRecord.Builder(); } } } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageId.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageId.java index dc3082d8c3..af8bae489a 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageId.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageId.java @@ -12,23 +12,23 @@ public class StorageId { private final byte[] raw; public static StorageId forContact(byte[] raw) { - return new StorageId(ManifestRecord.Identifier.Type.CONTACT_VALUE, Preconditions.checkNotNull(raw)); + return new StorageId(ManifestRecord.Identifier.Type.CONTACT.getValue(), Preconditions.checkNotNull(raw)); } public static StorageId forGroupV1(byte[] raw) { - return new StorageId(ManifestRecord.Identifier.Type.GROUPV1_VALUE, Preconditions.checkNotNull(raw)); + return new StorageId(ManifestRecord.Identifier.Type.GROUPV1.getValue(), Preconditions.checkNotNull(raw)); } public static StorageId forGroupV2(byte[] raw) { - return new StorageId(ManifestRecord.Identifier.Type.GROUPV2_VALUE, Preconditions.checkNotNull(raw)); + return new StorageId(ManifestRecord.Identifier.Type.GROUPV2.getValue(), Preconditions.checkNotNull(raw)); } public static StorageId forStoryDistributionList(byte[] raw) { - return new StorageId(ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST_VALUE, Preconditions.checkNotNull(raw)); + return new StorageId(ManifestRecord.Identifier.Type.STORY_DISTRIBUTION_LIST.getValue(), Preconditions.checkNotNull(raw)); } public static StorageId forAccount(byte[] raw) { - return new StorageId(ManifestRecord.Identifier.Type.ACCOUNT_VALUE, Preconditions.checkNotNull(raw)); + return new StorageId(ManifestRecord.Identifier.Type.ACCOUNT.getValue(), Preconditions.checkNotNull(raw)); } public static StorageId forType(byte[] raw, int type) { @@ -58,7 +58,7 @@ public class StorageId { public static boolean isKnownType(int val) { for (ManifestRecord.Identifier.Type type : ManifestRecord.Identifier.Type.values()) { - if (type != ManifestRecord.Identifier.Type.UNRECOGNIZED && type.getNumber() == val) { + if (type.getValue() == val) { return true; } } @@ -69,9 +69,7 @@ public class StorageId { int max = 0; for (ManifestRecord.Identifier.Type type : ManifestRecord.Identifier.Type.values()) { - if (type != ManifestRecord.Identifier.Type.UNRECOGNIZED) { - max = Math.max(type.getNumber(), max); - } + max = Math.max(type.getValue(), max); } return max; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageRecordProtoUtil.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageRecordProtoUtil.kt new file mode 100644 index 0000000000..ca5cec3778 --- /dev/null +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/StorageRecordProtoUtil.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +@file:JvmName("StorageRecordProtoUtil") + +package org.whispersystems.signalservice.api.storage + +import org.whispersystems.signalservice.internal.storage.protos.AccountRecord + +/** + * Provide helpers for various Storage Service protos. + */ +object StorageRecordProtoUtil { + @JvmStatic + val defaultAccountRecord by lazy { AccountRecord() } +} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/OptionalUtil.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/OptionalUtil.kt index 469d2419fd..03f2934df9 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/OptionalUtil.kt +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/OptionalUtil.kt @@ -1,6 +1,6 @@ package org.whispersystems.signalservice.api.util -import com.google.protobuf.ByteString +import okio.ByteString import java.util.Optional object OptionalUtil { @@ -41,7 +41,7 @@ object OptionalUtil { @JvmStatic fun absentIfEmpty(value: ByteString?): Optional { - return if (value == null || value.isEmpty) { + return if (value == null || value.size == 0) { Optional.empty() } else { Optional.of(value.toByteArray()) diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/ProtoUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/ProtoUtil.java index 75c72c82f9..df5825de56 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/ProtoUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/ProtoUtil.java @@ -1,8 +1,6 @@ package org.whispersystems.signalservice.api.util; -import com.google.protobuf.GeneratedMessageLite; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.UnknownFieldSetLite; +import com.squareup.wire.Message; import org.signal.libsignal.protocol.logging.Log; @@ -10,70 +8,50 @@ import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; +import okio.ByteString; + public final class ProtoUtil { private static final String TAG = ProtoUtil.class.getSimpleName(); private static final String DEFAULT_INSTANCE = "DEFAULT_INSTANCE"; - private ProtoUtil() { } + private ProtoUtil() {} /** * True if there are unknown fields anywhere inside the proto or its nested protos. */ @SuppressWarnings("rawtypes") - public static boolean hasUnknownFields(GeneratedMessageLite rootProto) { - try { - List allProtos = getInnerProtos(rootProto); - allProtos.add(rootProto); + public static boolean hasUnknownFields(Message rootProto) { + List allProtos = getInnerProtos(rootProto); + allProtos.add(rootProto); - for (GeneratedMessageLite proto : allProtos) { - Field field = GeneratedMessageLite.class.getDeclaredField("unknownFields"); - field.setAccessible(true); + for (Message proto : allProtos) { + ByteString unknownFields = proto.unknownFields(); - UnknownFieldSetLite unknownFields = (UnknownFieldSetLite) field.get(proto); - - if (unknownFields != null && unknownFields.getSerializedSize() > 0) { - return true; - } + if (unknownFields.size() > 0) { + return true; } - } catch (NoSuchFieldException | IllegalAccessException e) { - Log.w(TAG, "Failed to read proto private fields! Assuming no unknown fields."); } return false; } - /** - * This takes two arguments: A proto model, and the bytes of another proto model of the same type. - * This will take the proto model and append onto it any unknown fields from the serialized proto - * model. - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - public static Proto combineWithUnknownFields(Proto proto, byte[] serializedWithUnknownFields) - throws InvalidProtocolBufferException - { - return (Proto) proto.newBuilderForType() - .mergeFrom(serializedWithUnknownFields) - .mergeFrom(proto) - .build(); - } - /** * Recursively retrieves all inner complex proto types inside a given proto. */ @SuppressWarnings("rawtypes") - private static List getInnerProtos(GeneratedMessageLite proto) { - List innerProtos = new LinkedList<>(); + private static List getInnerProtos(Message proto) { + List innerProtos = new LinkedList<>(); try { Field[] fields = proto.getClass().getDeclaredFields(); for (Field field : fields) { - if (!field.getName().equals(DEFAULT_INSTANCE) && GeneratedMessageLite.class.isAssignableFrom(field.getType())) { + if (!field.getName().equals(DEFAULT_INSTANCE) && Message.class.isAssignableFrom(field.getType())) { field.setAccessible(true); - GeneratedMessageLite inner = (GeneratedMessageLite) field.get(proto); + Message inner = (Message) field.get(proto); if (inner != null) { innerProtos.add(inner); innerProtos.addAll(getInnerProtos(inner)); 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 9bd8d49d27..28e81a2423 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 @@ -59,6 +59,10 @@ public final class UuidUtil { return ByteString.copyFrom(toByteArray(uuid)); } + public static okio.ByteString toOkioByteString(UUID uuid) { + return okio.ByteString.of(toByteArray(uuid)); + } + public static UUID fromByteString(ByteString bytes) { return parseOrThrow(bytes.toByteArray()); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/crypto/PrimaryProvisioningCipher.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/crypto/PrimaryProvisioningCipher.java index 72b13f6382..fd9acbf063 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/crypto/PrimaryProvisioningCipher.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/crypto/PrimaryProvisioningCipher.java @@ -75,5 +75,4 @@ public class PrimaryProvisioningCipher { throw new AssertionError(e); } } - } 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 00d2b79ed7..7f261ce3f8 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 @@ -10,6 +10,7 @@ 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; import org.signal.libsignal.protocol.ecc.ECPublicKey; @@ -1309,19 +1310,19 @@ public class PushServiceSocket { public StorageManifest getStorageManifest(String authToken) throws IOException { try (Response response = makeStorageRequest(authToken, "/v1/storage/manifest", "GET", null, NO_HANDLER)) { - return StorageManifest.parseFrom(readBodyBytes(response)); + return StorageManifest.ADAPTER.decode(readBodyBytes(response)); } } public StorageManifest getStorageManifestIfDifferentVersion(String authToken, long version) throws IOException { try (Response response = makeStorageRequest(authToken, "/v1/storage/manifest/version/" + version, "GET", null, NO_HANDLER)) { - return StorageManifest.parseFrom(readBodyBytes(response)); + return StorageManifest.ADAPTER.decode(readBodyBytes(response)); } } public StorageItems readStorageItems(String authToken, ReadOperation operation) throws IOException { try (Response response = makeStorageRequest(authToken, "/v1/storage/read", "PUT", protobufRequestBody(operation), NO_HANDLER)) { - return StorageItems.parseFrom(readBodyBytes(response)); + return StorageItems.ADAPTER.decode(readBodyBytes(response)); } } @@ -1329,7 +1330,7 @@ public class PushServiceSocket { try (Response response = makeStorageRequest(authToken, "/v1/storage", "PUT", protobufRequestBody(writeOperation), NO_HANDLER)) { return Optional.empty(); } catch (ContactManifestMismatchException e) { - return Optional.of(StorageManifest.parseFrom(e.getResponseBody())); + return Optional.of(StorageManifest.ADAPTER.decode(e.getResponseBody())); } } @@ -1775,6 +1776,10 @@ public class PushServiceSocket { : null; } + private static RequestBody protobufRequestBody(Message protobufBody) { + return protobufBody != null ? RequestBody.create(MediaType.parse("application/x-protobuf"), protobufBody.encode()) + : null; + } private ListenableFuture submitServiceRequest(String urlFragment, String method, diff --git a/libsignal/service/src/main/proto/StorageService.proto b/libsignal/service/src/main/protowire/StorageService.proto similarity index 100% rename from libsignal/service/src/main/proto/StorageService.proto rename to libsignal/service/src/main/protowire/StorageService.proto diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/ProtoUtilTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/ProtoUtilTest.java deleted file mode 100644 index d73c5a1794..0000000000 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/util/ProtoUtilTest.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.whispersystems.signalservice.api.util; - -import com.google.protobuf.InvalidProtocolBufferException; - -import org.junit.Assert; -import org.junit.Test; -import org.thoughtcrime.securesms.util.testprotos.TestInnerMessage; -import org.thoughtcrime.securesms.util.testprotos.TestInnerMessageWithNewString; -import org.thoughtcrime.securesms.util.testprotos.TestPerson; -import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewFieldOnMessage; -import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewMessage; -import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewRepeatedString; -import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewString; -import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewStringAndInt; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class ProtoUtilTest { - - @Test - public void hasUnknownFields_noUnknowns() { - TestPerson person = TestPerson.newBuilder() - .setName("Peter Parker") - .setAge(23) - .build(); - - assertFalse(ProtoUtil.hasUnknownFields(person)); - } - - @Test - public void hasUnknownFields_unknownString() throws InvalidProtocolBufferException { - TestPersonWithNewString person = TestPersonWithNewString.newBuilder() - .setName("Peter Parker") - .setAge(23) - .setJob("Reporter") - .build(); - - TestPerson personWithUnknowns = TestPerson.parseFrom(person.toByteArray()); - - assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns)); - } - - @Test - public void hasUnknownFields_multipleUnknowns() throws InvalidProtocolBufferException { - TestPersonWithNewStringAndInt person = TestPersonWithNewStringAndInt.newBuilder() - .setName("Peter Parker") - .setAge(23) - .setJob("Reporter") - .setSalary(75_000) - .build(); - - TestPerson personWithUnknowns = TestPerson.parseFrom(person.toByteArray()); - - assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns)); - } - - @Test - public void hasUnknownFields_unknownMessage() throws InvalidProtocolBufferException { - TestPersonWithNewMessage person = TestPersonWithNewMessage.newBuilder() - .setName("Peter Parker") - .setAge(23) - .setJob(TestPersonWithNewMessage.Job.newBuilder() - .setTitle("Reporter") - .setSalary(75_000)) - .build(); - - TestPerson personWithUnknowns = TestPerson.parseFrom(person.toByteArray()); - - assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns)); - } - - @Test - public void hasUnknownFields_unknownInsideMessage() throws InvalidProtocolBufferException { - TestPersonWithNewFieldOnMessage person = TestPersonWithNewFieldOnMessage.newBuilder() - .setName("Peter Parker") - .setAge(23) - .setJob(TestPersonWithNewFieldOnMessage.Job.newBuilder() - .setTitle("Reporter") - .setSalary(75_000) - .setStartDate(100)) - .build(); - - TestPersonWithNewMessage personWithUnknowns = TestPersonWithNewMessage.parseFrom(person.toByteArray()); - - assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns)); - } - - @Test - public void hasUnknownFields_nullInnerMessage() throws InvalidProtocolBufferException { - TestPersonWithNewMessage person = TestPersonWithNewMessage.newBuilder() - .setName("Peter Parker") - .setAge(23) - .build(); - - TestPerson personWithUnknowns = TestPerson.parseFrom(person.toByteArray()); - - assertFalse(ProtoUtil.hasUnknownFields(personWithUnknowns)); - } - - @Test - public void combineWithUnknownFields_noUnknowns() throws InvalidProtocolBufferException { - TestPerson personWithUnknowns = TestPerson.newBuilder() - .setName("Peter Parker") - .setAge(23) - .build(); - - TestPerson localRepresentation = TestPerson.newBuilder() - .setName("Spider-Man") - .setAge(23) - .build(); - - TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray()); - TestPersonWithNewString reparsedPerson = TestPersonWithNewString.parseFrom(combinedWithUnknowns.toByteArray()); - - Assert.assertEquals("Spider-Man", reparsedPerson.getName()); - Assert.assertEquals(23, reparsedPerson.getAge()); - } - - @Test - public void combineWithUnknownFields_appendedString() throws InvalidProtocolBufferException { - TestPersonWithNewString personWithUnknowns = TestPersonWithNewString.newBuilder() - .setName("Peter Parker") - .setAge(23) - .setJob("Reporter") - .build(); - - TestPerson localRepresentation = TestPerson.newBuilder() - .setName("Spider-Man") - .setAge(23) - .build(); - - TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray()); - TestPersonWithNewString reparsedPerson = TestPersonWithNewString.parseFrom(combinedWithUnknowns.toByteArray()); - - Assert.assertEquals("Spider-Man", reparsedPerson.getName()); - Assert.assertEquals(23, reparsedPerson.getAge()); - Assert.assertEquals("Reporter", reparsedPerson.getJob()); - } - - @Test - public void combineWithUnknownFields_appendedRepeatedString() throws InvalidProtocolBufferException { - TestPersonWithNewRepeatedString personWithUnknowns = TestPersonWithNewRepeatedString.newBuilder() - .setName("Peter Parker") - .setAge(23) - .addJobs("Reporter") - .addJobs("Super Hero") - .build(); - - TestPerson localRepresentation = TestPerson.newBuilder() - .setName("Spider-Man") - .setAge(23) - .build(); - - TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray()); - TestPersonWithNewRepeatedString reparsedPerson = TestPersonWithNewRepeatedString.parseFrom(combinedWithUnknowns.toByteArray()); - - Assert.assertEquals("Spider-Man", reparsedPerson.getName()); - Assert.assertEquals(23, reparsedPerson.getAge()); - Assert.assertEquals(2, reparsedPerson.getJobsCount()); - Assert.assertEquals("Reporter", reparsedPerson.getJobs(0)); - Assert.assertEquals("Super Hero", reparsedPerson.getJobs(1)); - } - - @Test - public void combineWithUnknownFields_appendedStringAndInt() throws InvalidProtocolBufferException { - TestPersonWithNewStringAndInt personWithUnknowns = TestPersonWithNewStringAndInt.newBuilder() - .setName("Peter Parker") - .setAge(23) - .setJob("Reporter") - .setSalary(75_000) - .build(); - - TestPerson localRepresentation = TestPerson.newBuilder() - .setName("Spider-Man") - .setAge(23) - .build(); - - TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray()); - TestPersonWithNewStringAndInt reparsedPerson = TestPersonWithNewStringAndInt.parseFrom(combinedWithUnknowns.toByteArray()); - - Assert.assertEquals("Spider-Man", reparsedPerson.getName()); - Assert.assertEquals(23, reparsedPerson.getAge()); - Assert.assertEquals("Reporter", reparsedPerson.getJob()); - Assert.assertEquals(75_000, reparsedPerson.getSalary()); - } - - @Test - public void combineWithUnknownFields_appendedMessage() throws InvalidProtocolBufferException { - TestPersonWithNewMessage personWithUnknowns = TestPersonWithNewMessage.newBuilder() - .setName("Peter Parker") - .setAge(23) - .setJob(TestPersonWithNewMessage.Job.newBuilder() - .setTitle("Reporter") - .setSalary(75_000)) - .build(); - - TestPerson localRepresentation = TestPerson.newBuilder() - .setName("Spider-Man") - .setAge(23) - .build(); - - TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray()); - TestPersonWithNewMessage reparsedPerson = TestPersonWithNewMessage.parseFrom(combinedWithUnknowns.toByteArray()); - - Assert.assertEquals("Spider-Man", reparsedPerson.getName()); - Assert.assertEquals(23, reparsedPerson.getAge()); - Assert.assertEquals("Reporter", reparsedPerson.getJob().getTitle()); - Assert.assertEquals(75_000, reparsedPerson.getJob().getSalary()); - } - - /** - * This isn't ideal behavior. This is more to show how something works. In the future, it'd be - * nice to support inner unknown fields. - */ - @Test - public void combineWithUnknownFields_innerMessagesUnknownsIgnored() throws InvalidProtocolBufferException { - TestInnerMessageWithNewString test = TestInnerMessageWithNewString.newBuilder() - .setInner(TestInnerMessageWithNewString.Inner.newBuilder() - .setA("a1") - .setB("b1") - .build()) - .build(); - - TestInnerMessage localRepresentation = TestInnerMessage.newBuilder() - .setInner(TestInnerMessage.Inner.newBuilder() - .setA("a2") - .build()) - .build(); - - TestInnerMessage combined = ProtoUtil.combineWithUnknownFields(localRepresentation, test.toByteArray()); - TestInnerMessageWithNewString reparsedTest = TestInnerMessageWithNewString.parseFrom(combined.toByteArray()); - - Assert.assertEquals("a2", reparsedTest.getInner().getA()); - Assert.assertEquals("b1", reparsedTest.getInner().getB()); - } -} diff --git a/libsignal/service/src/test/proto/Test.proto b/libsignal/service/src/test/proto/Test.proto deleted file mode 100644 index a4543b47ae..0000000000 --- a/libsignal/service/src/test/proto/Test.proto +++ /dev/null @@ -1,70 +0,0 @@ -syntax = "proto3"; - -package signal; - -option java_package = "org.thoughtcrime.securesms.util.testprotos"; -option java_multiple_files = true; - -message TestPerson { - string name = 1; - int32 age = 2; -} - -message TestPersonWithNewString { - string name = 1; - int32 age = 2; - string job = 3; -} - -message TestPersonWithNewRepeatedString { - string name = 1; - int32 age = 2; - repeated string jobs = 3; -} - -message TestPersonWithNewStringAndInt { - string name = 1; - int32 age = 2; - string job = 3; - int32 salary = 4; -} - -message TestPersonWithNewMessage { - message Job { - string title = 1; - uint32 salary = 2; - } - - string name = 1; - int32 age = 2; - Job job = 3; -} - -message TestPersonWithNewFieldOnMessage { - message Job { - string title = 1; - uint32 salary = 2; - uint64 startDate = 3; - } - - string name = 1; - int32 age = 2; - Job job = 3; -} - -message TestInnerMessage { - message Inner { - string a = 1; - } - - Inner inner = 1; -} - -message TestInnerMessageWithNewString { - message Inner { - string a = 1; - string b = 2; - } - - Inner inner = 1; -} \ No newline at end of file