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 ed95f6c680..4757e4f830 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 @@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.testing.success import org.thoughtcrime.securesms.testing.timeout import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.internal.push.MismatchedDevices import org.whispersystems.signalservice.internal.push.PreKeyState import java.util.UUID @@ -73,7 +74,7 @@ class ChangeNumberViewModelTest { fun testChangeNumber_givenOnlyPrimaryAndNoRegLock() { // GIVEN val aci = Recipient.self().requireServiceId() - val newPni = ServiceId.from(UUID.randomUUID()) + val newPni = PNI.from(UUID.randomUUID()) lateinit var changeNumberRequest: ChangePhoneNumberRequest lateinit var setPreKeysRequest: PreKeyState @@ -180,7 +181,7 @@ class ChangeNumberViewModelTest { val aci = Recipient.self().requireServiceId() val oldPni = Recipient.self().requirePni() val oldE164 = Recipient.self().requireE164() - val newPni = ServiceId.from(UUID.randomUUID()) + val newPni = PNI.from(UUID.randomUUID()) lateinit var changeNumberRequest: ChangePhoneNumberRequest lateinit var setPreKeysRequest: PreKeyState @@ -225,7 +226,7 @@ class ChangeNumberViewModelTest { fun testChangeNumber_givenOnlyPrimaryAndRegistrationLock() { // GIVEN val aci = Recipient.self().requireServiceId() - val newPni = ServiceId.from(UUID.randomUUID()) + val newPni = PNI.from(UUID.randomUUID()) lateinit var changeNumberRequest: ChangePhoneNumberRequest lateinit var setPreKeysRequest: PreKeyState @@ -269,7 +270,7 @@ class ChangeNumberViewModelTest { fun testChangeNumber_givenMismatchedDevicesOnFirstCall() { // GIVEN val aci = Recipient.self().requireServiceId() - val newPni = ServiceId.from(UUID.randomUUID()) + val newPni = PNI.from(UUID.randomUUID()) lateinit var changeNumberRequest: ChangePhoneNumberRequest lateinit var setPreKeysRequest: PreKeyState @@ -313,7 +314,7 @@ class ChangeNumberViewModelTest { fun testChangeNumber_givenRegLockAndMismatchedDevicesOnFirstTwoCalls() { // GIVEN val aci = Recipient.self().requireServiceId() - val newPni = ServiceId.from(UUID.randomUUID()) + val newPni = PNI.from(UUID.randomUUID()) lateinit var changeNumberRequest: ChangePhoneNumberRequest lateinit var setPreKeysRequest: PreKeyState diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/DistributionListTablesTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/DistributionListTablesTest.kt index dde6f7a7f9..df616f9c70 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/DistributionListTablesTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/DistributionListTablesTest.kt @@ -7,7 +7,7 @@ import org.thoughtcrime.securesms.database.model.DistributionListId import org.thoughtcrime.securesms.database.model.DistributionListRecord import org.thoughtcrime.securesms.database.model.StoryType import org.thoughtcrime.securesms.recipients.RecipientId -import org.whispersystems.signalservice.api.push.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.util.UUID class DistributionListTablesTest { diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt index cb60fa48fd..12a7cede4f 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/MessageTableTest_gifts.kt @@ -10,9 +10,8 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.UUID @Suppress("ClassName") @@ -34,7 +33,7 @@ class MessageTableTest_gifts { SignalStore.account().setAci(localAci) SignalStore.account().setPni(localPni) - recipients = (0 until 5).map { SignalDatabase.recipients.getOrInsertFromServiceId(ServiceId.from(UUID.randomUUID())) } + recipients = (0 until 5).map { SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID())) } } @Test diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/MmsTableTest_stories.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/MmsTableTest_stories.kt index 7f626bdedf..4c863af0e2 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/MmsTableTest_stories.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/MmsTableTest_stories.kt @@ -16,9 +16,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.mms.IncomingMediaMessage import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.UUID import java.util.concurrent.TimeUnit @@ -45,7 +44,7 @@ class MmsTableTest_stories { SignalStore.account().setPni(localPni) myStory = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromDistributionListId(DistributionListId.MY_STORY)) - recipients = (0 until 5).map { SignalDatabase.recipients.getOrInsertFromServiceId(ServiceId.from(UUID.randomUUID())) } + recipients = (0 until 5).map { SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID())) } releaseChannelRecipient = Recipient.resolved(SignalDatabase.recipients.insertReleaseChannelRecipient()) SignalStore.releaseChannelValues().setReleaseChannelRecipientId(releaseChannelRecipient.id) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt index e9559c9941..e17b679af9 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest.kt @@ -13,8 +13,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.testing.SignalActivityRule import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.FeatureFlagsAccessor -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.UUID @RunWith(AndroidJUnit4::class) @@ -173,10 +173,10 @@ class RecipientTableTest { SignalDatabase.recipients.markUnregistered(mainId) - val byAci: RecipientId = SignalDatabase.recipients.getByServiceId(ACI_A).get() + val byAci: RecipientId = SignalDatabase.recipients.getByAci(ACI_A).get() val byE164: RecipientId = SignalDatabase.recipients.getByE164(E164_A).get() - val byPni: RecipientId = SignalDatabase.recipients.getByServiceId(PNI_A).get() + val byPni: RecipientId = SignalDatabase.recipients.getByPni(PNI_A).get() assertEquals(mainId, byAci) assertEquals(byE164, byPni) @@ -192,10 +192,10 @@ class RecipientTableTest { SignalDatabase.recipients.splitForStorageSync(mainRecord.storageId!!) - val byAci: RecipientId = SignalDatabase.recipients.getByServiceId(ACI_A).get() + val byAci: RecipientId = SignalDatabase.recipients.getByAci(ACI_A).get() val byE164: RecipientId = SignalDatabase.recipients.getByE164(E164_A).get() - val byPni: RecipientId = SignalDatabase.recipients.getByServiceId(PNI_A).get() + val byPni: RecipientId = SignalDatabase.recipients.getByPni(PNI_A).get() assertEquals(mainId, byAci) assertEquals(byE164, byPni) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt index afc28b1e7f..5bf7284e00 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt @@ -7,6 +7,7 @@ import org.hamcrest.MatcherAssert import org.hamcrest.Matchers import org.junit.Assert import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Assert.assertTrue @@ -14,6 +15,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.signal.core.util.SqlUtil +import org.signal.core.util.exists import org.signal.core.util.requireLong import org.signal.core.util.requireNonNullString import org.signal.core.util.select @@ -36,14 +38,13 @@ import org.thoughtcrime.securesms.mms.IncomingMediaMessage import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId -import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage import org.thoughtcrime.securesms.sms.IncomingTextMessage import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.FeatureFlagsAccessor -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI -import org.whispersystems.signalservice.api.push.ServiceId +import org.thoughtcrime.securesms.util.Util +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.Optional import java.util.UUID @@ -59,6 +60,21 @@ class RecipientTableTest_getAndPossiblyMerge { FeatureFlagsAccessor.forceValue(FeatureFlags.PHONE_NUMBER_PRIVACY, true) } + @Test + fun single() { + test("merge, e164 + pni reassigned, aci abandoned") { + given(E164_A, PNI_A, ACI_A) + given(E164_B, PNI_B, ACI_B) + + process(E164_A, PNI_A, ACI_B) + + expect(null, null, ACI_A) + expect(E164_A, PNI_A, ACI_B) + + expectChangeNumberEvent() + } + } + @Test fun allNonMergeTests() { test("e164-only insert") { @@ -69,7 +85,7 @@ class RecipientTableTest_getAndPossiblyMerge { assertEquals(RecipientTable.RegisteredState.UNKNOWN, record.registered) } - test("pni-only insert") { + test("pni-only insert", exception = IllegalArgumentException::class.java) { val id = process(null, PNI_A, null) expect(null, PNI_A, null) @@ -84,6 +100,21 @@ class RecipientTableTest_getAndPossiblyMerge { val record = SignalDatabase.recipients.getRecord(id) assertEquals(RecipientTable.RegisteredState.REGISTERED, record.registered) } + + test("e164+pni insert") { + process(E164_A, PNI_A, null) + expect(E164_A, PNI_A, null) + } + + test("e164+aci insert") { + process(E164_A, null, ACI_A) + expect(E164_A, null, ACI_A) + } + + test("e164+pni+aci insert") { + process(E164_A, PNI_A, ACI_A) + expect(E164_A, PNI_A, ACI_A) + } } @Test @@ -167,6 +198,12 @@ class RecipientTableTest_getAndPossiblyMerge { expectSessionSwitchoverEvent(E164_A) } + test("e164 and pni matches, all provided, new aci, existing pni session, pni-verified") { + given(E164_A, PNI_A, null, pniSession = true) + process(E164_A, PNI_A, ACI_A, pniVerified = true) + expect(E164_A, PNI_A, ACI_A) + } + test("e164 and aci matches, all provided, new pni") { given(E164_A, null, ACI_A) process(E164_A, PNI_A, ACI_A) @@ -309,6 +346,26 @@ class RecipientTableTest_getAndPossiblyMerge { expectChangeNumberEvent() } + test("steal, pni is changed") { + given(E164_A, PNI_B, ACI_A) + given(E164_B, PNI_A, null) + + process(E164_A, PNI_A, null) + + expect(E164_A, PNI_A, ACI_A) + expect(E164_B, null, null) + } + + test("steal, pni is changed, aci left behind") { + given(E164_B, PNI_A, ACI_A) + given(E164_A, PNI_B, null) + + process(E164_A, PNI_A, null) + + expect(E164_B, null, ACI_A) + expect(E164_A, PNI_A, null) + } + test("steal, e164+pni & e164+pni, no aci provided, no pni session") { given(E164_A, PNI_B, null) given(E164_B, PNI_A, null) @@ -502,7 +559,7 @@ class RecipientTableTest_getAndPossiblyMerge { expectThreadMergeEvent(E164_A) } - test("merge, e164+pni & aci, pni session, thread merge shadows") { + test("merge, e164+pni & aci, pni session, thread merge shadows SSE") { given(E164_A, PNI_A, null, pniSession = true) given(null, null, ACI_A) @@ -600,6 +657,18 @@ class RecipientTableTest_getAndPossiblyMerge { expectThreadMergeEvent(E164_A) } + test("merge, e164 + pni reassigned, aci abandoned") { + given(E164_A, PNI_A, ACI_A) + given(E164_B, PNI_B, ACI_B) + + process(E164_A, PNI_A, ACI_B) + + expect(null, null, ACI_A) + expect(E164_A, PNI_A, ACI_B) + + expectChangeNumberEvent() + } + test("local user, local e164 and aci provided, changeSelf=false, leave e164 alone") { given(E164_SELF, null, ACI_SELF) given(null, null, ACI_A) @@ -768,9 +837,15 @@ class RecipientTableTest_getAndPossiblyMerge { } private fun identityKey(value: Byte): IdentityKey { + val byteArray = ByteArray(32) + byteArray[0] = value + return identityKey(byteArray) + } + + private fun identityKey(value: ByteArray): IdentityKey { val bytes = ByteArray(33) bytes[0] = 0x05 - bytes[1] = value + value.copyInto(bytes, 1) return IdentityKey(bytes) } @@ -873,8 +948,8 @@ class RecipientTableTest_getAndPossiblyMerge { generatedIds += id if (createThread) { // Create a thread and throw a dummy message in it so it doesn't get automatically deleted - SignalDatabase.threads.getOrCreateThreadIdFor(Recipient.resolved(id)) - SignalDatabase.messages.insertMessageInbox(IncomingEncryptedMessage(IncomingTextMessage(id, 1, (Math.random() * Long.MAX_VALUE).toLong(), 0, 0, "", Optional.empty(), 0, false, ""), "")) + val result = SignalDatabase.messages.insertMessageInbox(smsMessage(sender = id, time = (Math.random() * 10000000).toLong(), body = "1")) + SignalDatabase.threads.markAsActiveEarly(result.get().threadId) } if (pniSession) { @@ -885,11 +960,34 @@ class RecipientTableTest_getAndPossiblyMerge { SignalDatabase.sessions.store(pni, SignalProtocolAddress(pni.toString(), 1), SessionRecord()) } + if (aci != null) { + SignalDatabase.identities.saveIdentity( + addressName = aci.toString(), + recipientId = id, + identityKey = identityKey(Util.getSecretBytes(32)), + verifiedStatus = IdentityTable.VerifiedStatus.DEFAULT, + firstUse = true, + timestamp = 0, + nonBlockingApproval = false + ) + } + if (pni != null) { + SignalDatabase.identities.saveIdentity( + addressName = pni.toString(), + recipientId = id, + identityKey = identityKey(Util.getSecretBytes(32)), + verifiedStatus = IdentityTable.VerifiedStatus.DEFAULT, + firstUse = true, + timestamp = 0, + nonBlockingApproval = false + ) + } + return id } fun process(e164: String?, pni: PNI?, aci: ACI?, changeSelf: Boolean = false, pniVerified: Boolean = false): RecipientId { - outputRecipientId = SignalDatabase.recipients.getAndPossiblyMerge(serviceId = aci ?: pni, pni = pni, e164 = e164, pniVerified = pniVerified, changeSelf = changeSelf) + outputRecipientId = SignalDatabase.recipients.getAndPossiblyMerge(aci = aci, pni = pni, e164 = e164, pniVerified = pniVerified, changeSelf = changeSelf) generatedIds += outputRecipientId return outputRecipientId } @@ -903,15 +1001,15 @@ class RecipientTableTest_getAndPossiblyMerge { val expected = RecipientTuple( e164 = e164, pni = pni, - serviceId = aci ?: pni + aci = aci ) val actual = RecipientTuple( e164 = recipient.e164.orElse(null), pni = recipient.pni.orElse(null), - serviceId = recipient.serviceId.orElse(null) + aci = recipient.aci.orElse(null) ) - assertEquals(expected, actual) + assertEquals("Recipient $id did not match expected result!", expected, actual) } fun expectDeleted() { @@ -919,21 +1017,21 @@ class RecipientTableTest_getAndPossiblyMerge { } fun expectDeleted(id: RecipientId) { - SignalDatabase.rawDatabase - .select("1") - .from(RecipientTable.TABLE_NAME) + val found = SignalDatabase.rawDatabase + .exists(RecipientTable.TABLE_NAME) .where("${RecipientTable.ID} = ?", id) .run() - .use { !it.moveToFirst() } + + assertFalse("Expected $id to be deleted, but it's still present!", found) } fun expectChangeNumberEvent() { - assertEquals(1, SignalDatabase.messages.getChangeNumberMessageCount(outputRecipientId)) + assertEquals("Missing change number event!", 1, SignalDatabase.messages.getChangeNumberMessageCount(outputRecipientId)) changeNumberExpected = true } fun expectNoChangeNumberEvent() { - assertEquals(0, SignalDatabase.messages.getChangeNumberMessageCount(outputRecipientId)) + assertEquals("Unexpected change number event!", 0, SignalDatabase.messages.getChangeNumberMessageCount(outputRecipientId)) changeNumberExpected = false } @@ -943,42 +1041,39 @@ class RecipientTableTest_getAndPossiblyMerge { fun expectSessionSwitchoverEvent(recipientId: RecipientId, e164: String) { val event: SessionSwitchoverEvent? = getLatestSessionSwitchoverEvent(recipientId) - assertNotNull(event) + assertNotNull("Missing session switchover event! Expected one with e164 = $e164", event) assertEquals(e164, event!!.e164) sessionSwitchoverExpected = true } fun expectNoSessionSwitchoverEvent() { - assertNull(getLatestSessionSwitchoverEvent(outputRecipientId)) + assertNull("Unexpected session switchover event!", getLatestSessionSwitchoverEvent(outputRecipientId)) } fun expectThreadMergeEvent(previousE164: String) { val event: ThreadMergeEvent? = getLatestThreadMergeEvent(outputRecipientId) - assertNotNull(event) - assertEquals(previousE164, event!!.previousE164) + assertNotNull("Missing thread merge event! Expected one with e164 = $previousE164", event) + assertEquals("E164 on thread merge event doesn't match!", previousE164, event!!.previousE164) threadMergeExpected = true } fun expectNoThreadMergeEvent() { - assertNull(getLatestThreadMergeEvent(outputRecipientId)) + assertNull("Unexpected thread merge event!", getLatestThreadMergeEvent(outputRecipientId)) } private fun insert(e164: String?, pni: PNI?, aci: ACI?): RecipientId { - val serviceIdString: String? = (aci ?: pni)?.toString() - val pniString: String? = pni?.toString() - val id: Long = SignalDatabase.rawDatabase.insert( RecipientTable.TABLE_NAME, null, contentValuesOf( RecipientTable.PHONE to e164, - RecipientTable.SERVICE_ID to serviceIdString, - RecipientTable.PNI_COLUMN to pniString, + RecipientTable.ACI_COLUMN to aci?.toString(), + RecipientTable.PNI_COLUMN to pni?.toString(), RecipientTable.REGISTERED to RecipientTable.RegisteredState.REGISTERED.id ) ) - assertTrue("Failed to insert! E164: $e164, ServiceId: $serviceIdString, PNI: $pniString", id > 0) + assertTrue("Failed to insert! E164: $e164, ACI: $aci, PNI: $pni", id > 0) return RecipientId.from(id) } @@ -987,14 +1082,14 @@ class RecipientTableTest_getAndPossiblyMerge { data class RecipientTuple( val e164: String?, val pni: PNI?, - val serviceId: ServiceId? + val aci: ACI? ) { /** * The intent here is to give nice diffs with the name of the constants rather than the values. */ override fun toString(): String { - return "(${e164.e164String()}, ${pni.pniString()}, ${serviceId.serviceIdString()})" + return "(${e164.e164String()}, ${pni.pniString()}, ${aci.aciString()})" } private fun String?.e164String(): String { @@ -1018,12 +1113,9 @@ class RecipientTableTest_getAndPossiblyMerge { } ?: "null" } - private fun ServiceId?.serviceIdString(): String { + private fun ACI?.aciString(): String { return this?.let { when (it) { - PNI_A -> "PNI_A" - PNI_B -> "PNI_B" - PNI_SELF -> "PNI_SELF" ACI_A -> "ACI_A" ACI_B -> "ACI_B" ACI_SELF -> "ACI_SELF" diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt index a67316513c..d1e1080799 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/SmsDatabaseTest_collapseJoinRequestEventsIfPossible.kt @@ -21,9 +21,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.sms.IncomingGroupUpdateMessage import org.thoughtcrime.securesms.sms.IncomingTextMessage -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.Optional import java.util.UUID @@ -283,8 +282,8 @@ class SmsDatabaseTest_collapseJoinRequestEventsIfPossible { } companion object { - private val aliceServiceId: ServiceId = ACI.from(UUID.fromString("3436efbe-5a76-47fa-a98a-7e72c948a82e")) - private val bobServiceId: ServiceId = ACI.from(UUID.fromString("8de7f691-0b60-4a68-9cd9-ed2f8453f9ed")) + private val aliceServiceId: ACI = ACI.from(UUID.fromString("3436efbe-5a76-47fa-a98a-7e72c948a82e")) + private val bobServiceId: ACI = ACI.from(UUID.fromString("8de7f691-0b60-4a68-9cd9-ed2f8453f9ed")) private val masterKey = GroupMasterKey(Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) private val groupId = GroupId.v2(masterKey) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/StorySendTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/StorySendTableTest.kt index e8ee5b2ec8..5064e8d653 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/StorySendTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/StorySendTableTest.kt @@ -21,7 +21,7 @@ import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.testing.SignalActivityRule import org.whispersystems.signalservice.api.push.DistributionId -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.util.UUID @RunWith(AndroidJUnit4::class) @@ -465,7 +465,7 @@ class StorySendTableTest { private fun makeRecipients(count: Int): List { return (1..count).map { - SignalDatabase.recipients.getOrInsertFromServiceId(ServiceId.from(UUID.randomUUID())) + SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID())) } } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_active.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_active.kt index 55e8251ea2..0385e39175 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_active.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_active.kt @@ -14,7 +14,7 @@ import org.junit.Test import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.testing.SignalDatabaseRule -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.util.UUID @Suppress("ClassName") @@ -28,7 +28,7 @@ class ThreadTableTest_active { @Before fun setUp() { - recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ServiceId.from(UUID.randomUUID()))) + recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID()))) } @Test diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_pinned.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_pinned.kt index 8a5165baac..5efcac8834 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_pinned.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_pinned.kt @@ -9,7 +9,7 @@ import org.signal.core.util.CursorUtil import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.testing.SignalDatabaseRule -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.util.UUID @Suppress("ClassName") @@ -23,7 +23,7 @@ class ThreadTableTest_pinned { @Before fun setUp() { - recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ServiceId.from(UUID.randomUUID()))) + recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID()))) } @Test diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_recents.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_recents.kt index 5e0058f984..d112370fd4 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_recents.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/ThreadTableTest_recents.kt @@ -10,7 +10,7 @@ import org.signal.core.util.CursorUtil import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.testing.SignalDatabaseRule -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.util.UUID @Suppress("ClassName") @@ -25,7 +25,7 @@ class ThreadTableTest_recents { @Before fun setUp() { - recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ServiceId.from(UUID.randomUUID()))) + recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID()))) } @Test diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessorTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessorTest.kt index 2e65da6bca..4a28ecc122 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessorTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageContentProcessorTest.kt @@ -46,9 +46,9 @@ abstract class MessageContentProcessorTest { ): SignalServiceContentProto { return TestProtos.build { serviceContent( - localAddress = address(uuid = harness.self.requireServiceId().uuid()).build(), + localAddress = address(uuid = harness.self.requireServiceId().rawUuid).build(), metadata = metadata( - address = address(uuid = messageSender.requireServiceId().uuid()).build() + address = address(uuid = messageSender.requireServiceId().rawUuid).build() ).build() ).apply { content = content().apply { 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 e5919a777c..9e81f991d9 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt @@ -14,8 +14,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.FeatureFlagsAccessor -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.storage.SignalContactRecord import org.whispersystems.signalservice.api.storage.StorageId import org.whispersystems.signalservice.internal.storage.protos.ContactRecord @@ -39,14 +39,14 @@ class ContactRecordProcessorTest { setStorageId(originalId, STORAGE_ID_A) val remote1 = buildRecord(STORAGE_ID_B) { - setServiceId(ACI_A.toString()) + setAci(ACI_A.toString()) setUnregisteredAtTimestamp(100) } val remote2 = buildRecord(STORAGE_ID_C) { - setServiceId(PNI_A.toString()) - setServicePni(PNI_A.toString()) - setServiceE164(E164_A) + setAci(PNI_A.toString()) + setPni(PNI_A.toString()) + setE164(E164_A) } // WHEN @@ -54,10 +54,10 @@ class ContactRecordProcessorTest { subject.process(listOf(remote1, remote2), StorageSyncHelper.KEY_GENERATOR) // THEN - val byAci: RecipientId = SignalDatabase.recipients.getByServiceId(ACI_A).get() + val byAci: RecipientId = SignalDatabase.recipients.getByAci(ACI_A).get() val byE164: RecipientId = SignalDatabase.recipients.getByE164(E164_A).get() - val byPni: RecipientId = SignalDatabase.recipients.getByServiceId(PNI_A).get() + val byPni: RecipientId = SignalDatabase.recipients.getByPni(PNI_A).get() assertEquals(originalId, byAci) assertEquals(byE164, byPni) @@ -71,14 +71,14 @@ class ContactRecordProcessorTest { setStorageId(originalId, STORAGE_ID_A) val remote1 = buildRecord(STORAGE_ID_B) { - setServiceId(ACI_A.toString()) + setAci(ACI_A.toString()) setUnregisteredAtTimestamp(0) } val remote2 = buildRecord(STORAGE_ID_C) { - setServiceId(PNI_A.toString()) - setServicePni(PNI_A.toString()) - setServiceE164(E164_A) + setAci(PNI_A.toString()) + setPni(PNI_A.toString()) + setE164(E164_A) } // WHEN @@ -86,7 +86,7 @@ class ContactRecordProcessorTest { subject.process(listOf(remote1, remote2), StorageSyncHelper.KEY_GENERATOR) // THEN - val byAci: RecipientId = SignalDatabase.recipients.getByServiceId(ACI_A).get() + val byAci: RecipientId = SignalDatabase.recipients.getByAci(ACI_A).get() val byE164: RecipientId = SignalDatabase.recipients.getByE164(E164_A).get() val byPni: RecipientId = SignalDatabase.recipients.getByPni(PNI_A).get() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt index 615430b425..0977d99211 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt @@ -27,7 +27,7 @@ class AliceClient(val serviceId: ServiceId, val e164: String, val trustRoot: ECK private val aliceSenderCertificate = FakeClientHelpers.createCertificateFor( trustRoot = trustRoot, - uuid = serviceId.uuid(), + uuid = serviceId.rawUuid, e164 = e164, deviceId = 1, identityKey = SignalStore.account().aciIdentityKey.publicKey.publicKey, diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt index e53cd147d2..954a248302 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt @@ -50,7 +50,7 @@ class BobClient(val serviceId: ServiceId, val e164: String, val identityKeyPair: private val serviceAddress = SignalServiceAddress(serviceId, e164) private val registrationId = KeyHelper.generateRegistrationId(false) private val aciStore = BobSignalServiceAccountDataStore(registrationId, identityKeyPair) - private val senderCertificate = FakeClientHelpers.createCertificateFor(trustRoot, serviceId.uuid(), e164, 1, identityKeyPair.publicKey.publicKey, 31337) + private val senderCertificate = FakeClientHelpers.createCertificateFor(trustRoot, serviceId.rawUuid, e164, 1, identityKeyPair.publicKey.publicKey, 31337) private val sessionLock = object : SignalSessionLock { private val lock = ReentrantLock() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt index 1f8b31c8a8..89a97893d9 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt @@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.registration.VerifyResponse import org.thoughtcrime.securesms.testing.GroupTestingUtils.asMember import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.api.profiles.SignalServiceProfile -import org.whispersystems.signalservice.api.push.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.internal.ServiceResponse import org.whispersystems.signalservice.internal.ServiceResponseProcessor diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt index 343d5f864e..4adebe0b15 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalDatabaseRule.kt @@ -4,8 +4,8 @@ import org.junit.rules.TestWatcher import org.junit.runner.Description import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.UUID /** diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt index 3c9c13f308..706e589eea 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/TestProtos.kt @@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.testing import com.google.protobuf.ByteString import org.signal.libsignal.zkgroup.groups.GroupMasterKey -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.internal.push.SignalServiceProtos import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2 @@ -17,7 +17,7 @@ class TestProtos private constructor() { uuid: UUID = UUID.randomUUID() ): AddressProto.Builder { return AddressProto.newBuilder() - .setUuid(ServiceId.from(uuid).toByteString()) + .setUuid(ACI.from(uuid).toByteString()) } fun metadata( diff --git a/app/src/benchmark/java/org/signal/benchmark/DummyAccountManagerFactory.kt b/app/src/benchmark/java/org/signal/benchmark/DummyAccountManagerFactory.kt index bebf6bbfe9..27f51b9f03 100644 --- a/app/src/benchmark/java/org/signal/benchmark/DummyAccountManagerFactory.kt +++ b/app/src/benchmark/java/org/signal/benchmark/DummyAccountManagerFactory.kt @@ -7,8 +7,8 @@ import org.thoughtcrime.securesms.push.AccountManagerFactory import org.thoughtcrime.securesms.util.FeatureFlags import org.whispersystems.signalservice.api.SignalServiceAccountManager import org.whispersystems.signalservice.api.account.PreKeyUpload -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration import java.io.IOException import java.util.Optional diff --git a/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt b/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt index 0bb7c6bf4e..167e4eb862 100644 --- a/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt +++ b/app/src/benchmark/java/org/signal/benchmark/setup/TestUsers.kt @@ -23,7 +23,7 @@ import org.thoughtcrime.securesms.registration.RegistrationUtil import org.thoughtcrime.securesms.registration.VerifyResponse import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.api.profiles.SignalServiceProfile -import org.whispersystems.signalservice.api.push.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.internal.ServiceResponse import org.whispersystems.signalservice.internal.ServiceResponseProcessor diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt index baa2f14019..c3c46fefb5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt @@ -93,7 +93,7 @@ sealed class CallLogRow { return FULL } - if (groupCallUpdateDetails.inCallUuidsList.contains(Recipient.self().requireServiceId().uuid().toString())) { + if (groupCallUpdateDetails.inCallUuidsList.contains(Recipient.self().requireAci().rawUuid.toString())) { return LOCAL_USER_JOINED } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberLockActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberLockActivity.kt index 41e4df1dff..e736c76c07 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberLockActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberLockActivity.kt @@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme import org.thoughtcrime.securesms.util.DynamicTheme -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.Objects private val TAG: String = Log.tag(ChangeNumberLockActivity::class.java) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt index 2926ccfb09..4699c3cc28 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt @@ -34,8 +34,7 @@ import org.whispersystems.signalservice.api.SvrNoDataException import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest import org.whispersystems.signalservice.api.account.PreKeyUpload import org.whispersystems.signalservice.api.kbs.MasterKey -import org.whispersystems.signalservice.api.push.PNI -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.push.ServiceIdType import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.push.SignedPreKeyEntity @@ -243,7 +242,7 @@ class ChangeNumberRepository( throw AssertionError("No change number metadata") } - val originalPni = ServiceId.fromByteString(metadata.previousPni) + val originalPni = PNI.parseOrThrow(metadata.previousPni) if (originalPni == pni) { Log.i(TAG, "No change has occurred, PNI is unchanged: $pni") diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt index cc717b4452..ba752d8279 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModel.kt @@ -27,7 +27,7 @@ import org.thoughtcrime.securesms.registration.viewmodel.BaseRegistrationViewMod import org.thoughtcrime.securesms.registration.viewmodel.NumberViewState import org.thoughtcrime.securesms.registration.viewmodel.SvrAuthCredentialSet import org.thoughtcrime.securesms.util.DefaultValueLiveData -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.push.exceptions.IncorrectCodeException import org.whispersystems.signalservice.internal.ServiceResponse import java.util.Objects diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/search/InternalSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/search/InternalSearchViewModel.kt index 87c15d5c28..7e91b4435b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/search/InternalSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/search/InternalSearchViewModel.kt @@ -8,7 +8,6 @@ package org.thoughtcrime.securesms.components.settings.app.internal.search import androidx.compose.runtime.MutableState import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable @@ -46,7 +45,7 @@ class InternalSearchViewModel : ViewModel() { InternalSearchResult( id = record.id, name = record.displayName(), - aci = record.serviceId?.toString(), + aci = record.aci?.toString(), pni = record.pni.toString(), groupId = record.groupId ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt index b66ff20163..dea0f1c751 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsViewModel.kt @@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.UsernameUtil -import org.whispersystems.signalservice.api.push.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException import java.io.IOException diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt index bc0ef7c561..f608b6f175 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt @@ -165,8 +165,11 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( .setTitle("Are you sure?") .setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() } .setPositiveButton(android.R.string.ok) { _, _ -> - if (recipient.hasServiceId()) { - SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireServiceId().toString()) + if (recipient.hasAci()) { + SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireAci().toString()) + } + if (recipient.hasPni()) { + SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requirePni().toString()) } } .show() @@ -182,14 +185,25 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( .setTitle("Are you sure?") .setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() } .setPositiveButton(android.R.string.ok) { _, _ -> + SignalDatabase.threads.deleteConversation(SignalDatabase.threads.getThreadIdIfExistsFor(recipient.id)) + if (recipient.hasServiceId()) { SignalDatabase.recipients.debugClearServiceIds(recipient.id) SignalDatabase.recipients.debugClearProfileData(recipient.id) - SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireServiceId().toString()) - ApplicationDependencies.getProtocolStore().aci().identities().delete(recipient.requireServiceId().toString()) - ApplicationDependencies.getProtocolStore().pni().identities().delete(recipient.requireServiceId().toString()) - SignalDatabase.threads.deleteConversation(SignalDatabase.threads.getThreadIdIfExistsFor(recipient.id)) } + + if (recipient.hasAci()) { + SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireAci().toString()) + SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requirePni(), addressName = recipient.requireAci().toString()) + ApplicationDependencies.getProtocolStore().aci().identities().delete(recipient.requireAci().toString()) + } + + if (recipient.hasPni()) { + SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requirePni().toString()) + SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requirePni(), addressName = recipient.requirePni().toString()) + ApplicationDependencies.getProtocolStore().aci().identities().delete(recipient.requirePni().toString()) + } + startActivity(MainActivity.clearTop(requireContext())) } .show() @@ -237,7 +251,7 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( SignalDatabase.recipients.debugClearE164AndPni(recipient.id) val splitRecipientId: RecipientId = if (FeatureFlags.phoneNumberPrivacy()) { - SignalDatabase.recipients.getAndPossiblyMergePnpVerified(recipient.pni.orElse(null), recipient.pni.orElse(null), recipient.requireE164()) + SignalDatabase.recipients.getAndPossiblyMergePnpVerified(null, recipient.pni.orElse(null), recipient.requireE164()) } else { SignalDatabase.recipients.getAndPossiblyMerge(recipient.pni.orElse(null), recipient.requireE164()) } @@ -281,7 +295,7 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( SignalDatabase.recipients.debugRemoveAci(recipient.id) - val aciRecipientId: RecipientId = SignalDatabase.recipients.getAndPossiblyMergePnpVerified(recipient.requireServiceId(), null, null) + val aciRecipientId: RecipientId = SignalDatabase.recipients.getAndPossiblyMergePnpVerified(recipient.requireAci(), null, null) recipient.profileKey?.let { profileKey -> SignalDatabase.recipients.setProfileKey(aciRecipientId, ProfileKey(profileKey)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryRefreshV2.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryRefreshV2.kt index fa2b6ad982..3a764a58e8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryRefreshV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryRefreshV2.kt @@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.FeatureFlags -import org.whispersystems.signalservice.api.push.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidTokenException import org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhaustedException import org.whispersystems.signalservice.api.services.CdsiV2Service diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelper.java b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelper.java index 80e7c9beb0..3ed8a5708e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelper.java @@ -4,7 +4,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.Arrays; import java.util.Collection; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index 17e6205fb4..9e6ba2ed6e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -50,7 +50,7 @@ import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.verify.VerifyIdentityActivity; -import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.Collection; import java.util.Locale; @@ -315,7 +315,7 @@ public final class ConversationUpdateItem extends FrameLayout liveBannedMembers = liveGroup.getBannedMembers(); liveFullMembers = Transformations.map(liveGroup.getFullMembers(), members -> members.stream() - .map(m -> m.getMember().requireServiceId().uuid()) + .map(m -> m.getMember().requireAci().getRawUuid()) .collect(Collectors.toSet())); liveIsSelfAdmin.observe(lifecycleOwner, updater); @@ -343,7 +343,7 @@ public final class ConversationUpdateItem extends FrameLayout Set bannedMembers = liveBannedMembers.getValue(); if (bannedMembers != null) { - return recipient.getServiceId().isPresent() && bannedMembers.contains(recipient.requireServiceId().uuid()); + return recipient.getServiceId().isPresent() && bannedMembers.contains(recipient.requireServiceId().getRawUuid()); } return false; } @@ -355,7 +355,7 @@ public final class ConversationUpdateItem extends FrameLayout Set members = liveFullMembers.getValue(); if (members != null) { - return recipient.getServiceId().isPresent() && members.contains(recipient.requireServiceId().uuid()); + return recipient.hasAci() && members.contains(recipient.requireAci().getRawUuid()); } return false; } @@ -446,12 +446,12 @@ public final class ConversationUpdateItem extends FrameLayout } }); } else if (conversationMessage.getMessageRecord().isGroupCall()) { - UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true); - Collection sids = updateDescription.getMentioned(); + UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true); + Collection acis = updateDescription.getMentioned(); int text = 0; - if (Util.hasItems(sids)) { - if (sids.contains(SignalStore.account().requireAci())) { + if (Util.hasItems(acis)) { + if (acis.contains(SignalStore.account().requireAci())) { text = R.string.ConversationUpdateItem_return_to_call; } else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).getIsCallFull()) { text = R.string.ConversationUpdateItem_call_is_full; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java index 069b65358f..31589b2ef6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java @@ -176,7 +176,7 @@ public final class SafetyNumberChangeRepository { Log.d(TAG, "Saving identity result: " + result); if (result == SignalIdentityKeyStore.SaveResult.NO_CHANGE) { Log.i(TAG, "Archiving sessions explicitly as they appear to be out of sync."); - ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(changedRecipient.getRecipient().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID); + ApplicationDependencies.getProtocolStore().aci().sessions().archiveSessions(changedRecipient.getRecipient().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID); ApplicationDependencies.getProtocolStore().aci().sessions().archiveSiblingSessions(mismatchAddress); SignalDatabase.senderKeyShared().deleteAllFor(changedRecipient.getRecipient().getId()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java index 5cf4c7b570..c725ae28af 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java @@ -69,8 +69,8 @@ public class SignalBaseIdentityKeyStore { public @NonNull SaveResult saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) { try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { - IdentityStoreRecord identityRecord = cache.get(address.getName()); - RecipientId recipientId = RecipientId.fromSidOrE164(address.getName()); + IdentityStoreRecord identityRecord = cache.get(address.getName()); + RecipientId recipientId = RecipientId.fromSidOrE164(address.getName()); if (identityRecord == null) { Log.i(TAG, "Saving new identity for " + address); diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java index 4a8a914bbb..da84874432 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java @@ -6,7 +6,6 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.signal.libsignal.protocol.NoSessionException; import org.signal.libsignal.protocol.SignalProtocolAddress; -import org.signal.libsignal.protocol.message.CiphertextMessage; import org.signal.libsignal.protocol.state.SessionRecord; import org.thoughtcrime.securesms.crypto.ReentrantSessionLock; import org.thoughtcrime.securesms.database.SessionTable; @@ -126,13 +125,23 @@ public class TextSecureSessionStore implements SignalServiceSessionStore { } } } + + public void archiveSession(@NonNull ServiceId serviceId, int deviceId) { + try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { + archiveSession(new SignalProtocolAddress(serviceId.toString(), deviceId)); + } + } - public void archiveSession(@NonNull RecipientId recipientId, int deviceId) { + public void archiveSessions(@NonNull RecipientId recipientId, int deviceId) { try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { Recipient recipient = Recipient.resolved(recipientId); - if (recipient.hasServiceId()) { - archiveSession(new SignalProtocolAddress(recipient.requireServiceId().toString(), deviceId)); + if (recipient.hasAci()) { + archiveSession(new SignalProtocolAddress(recipient.requireAci().toString(), deviceId)); + } + + if (recipient.hasPni()) { + archiveSession(new SignalProtocolAddress(recipient.requirePni().toString(), deviceId)); } if (recipient.hasE164()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt index 0e8481bc90..fc51ab6d75 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt @@ -34,7 +34,7 @@ import org.thoughtcrime.securesms.jobs.CallSyncEventJob import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent import java.util.UUID import java.util.concurrent.TimeUnit @@ -605,11 +605,11 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl fun insertOrUpdateGroupCallFromRingState( ringId: Long, groupRecipientId: RecipientId, - ringerUUID: UUID, + ringerAci: ACI, dateReceived: Long, ringState: RingUpdate ) { - val ringerRecipient = Recipient.externalPush(ServiceId.from(ringerUUID)) + val ringerRecipient = Recipient.externalPush(ringerAci) handleGroupRingState(ringId, groupRecipientId, ringerRecipient.id, dateReceived, ringState) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt index c846c02808..eb229c6dab 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt @@ -55,6 +55,7 @@ import org.whispersystems.signalservice.api.groupsv2.GroupChangeReconstruct import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.util.UuidUtil import java.io.Closeable import java.security.SecureRandom @@ -1215,7 +1216,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT val serviceId = recipient.serviceId return if (serviceId.isPresent) { - DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().uuid()) + DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().rawUuid) .map { it.role == Member.Role.ADMINISTRATOR } .orElse(false) } else { @@ -1232,7 +1233,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT return MemberLevel.NOT_A_MEMBER } - var memberLevel: Optional = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().uuid()) + var memberLevel: Optional = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().rawUuid) .map { member -> if (member.role == Member.Role.ADMINISTRATOR) { MemberLevel.ADMINISTRATOR @@ -1242,12 +1243,12 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT } if (memberLevel.isAbsent()) { - memberLevel = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, serviceId.get().uuid()) + memberLevel = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, serviceId.get().rawUuid) .map { MemberLevel.PENDING_MEMBER } } if (memberLevel.isAbsent()) { - memberLevel = DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.requestingMembersList, serviceId.get().uuid()) + memberLevel = DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.requestingMembersList, serviceId.get().rawUuid) .map { _ -> MemberLevel.REQUESTING_MEMBER } } @@ -1264,7 +1265,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT fun getMemberRecipientIds(memberSet: MemberSet): List { val includeSelf = memberSet.includeSelf - val selfUuid = SignalStore.account().requireAci().uuid() + val selfAciUuid = SignalStore.account().requireAci().rawUuid val recipients: MutableList = ArrayList(decryptedGroup.membersCount + decryptedGroup.pendingMembersCount) var unknownMembers = 0 @@ -1273,8 +1274,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT for (uuid in DecryptedGroupUtil.toUuidList(decryptedGroup.membersList)) { if (UuidUtil.UNKNOWN_UUID == uuid) { unknownMembers++ - } else if (includeSelf || selfUuid != uuid) { - recipients += RecipientId.from(ServiceId.from(uuid)) + } else if (includeSelf || selfAciUuid != uuid) { + recipients += RecipientId.from(ACI.from(uuid)) } } @@ -1282,8 +1283,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT for (uuid in DecryptedGroupUtil.pendingToUuidList(decryptedGroup.pendingMembersList)) { if (UuidUtil.UNKNOWN_UUID == uuid) { unknownPending++ - } else if (includeSelf || selfUuid != uuid) { - recipients += RecipientId.from(ServiceId.from(uuid)) + } else if (includeSelf || selfAciUuid != uuid) { + recipients += RecipientId.from(ACI.from(uuid)) } } } @@ -1301,7 +1302,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT .asSequence() .map { UuidUtil.fromByteStringOrNull(it.uuid) } .filterNotNull() - .map { ServiceId.from(it) } + .map { ACI.from(it) } .sortedBy { it.toString() } .toList() } @@ -1376,8 +1377,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT private fun gv2GroupActive(decryptedGroup: DecryptedGroup): Boolean { val aci = SignalStore.account().requireAci() - return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, aci.uuid()).isPresent || - DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, aci.uuid()).isPresent + return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, aci.rawUuid).isPresent || + DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, aci.rawUuid).isPresent } private fun List.toRecipientIds(): MutableList { @@ -1405,7 +1406,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT Log.w(TAG, "Saw an unknown UUID when mapping to RecipientIds!") null } else { - val id = RecipientId.from(ServiceId.from(uuid)) + val id = RecipientId.from(ACI.from(uuid)) val remapped = RemappedRecords.getInstance().getRecipient(id) if (remapped.isPresent) { Log.w(TAG, "Saw that $id remapped to $remapped. Using the mapping.") diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/IdentityTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/IdentityTable.kt index 7b865f1e7c..55178915a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/IdentityTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/IdentityTable.kt @@ -70,6 +70,14 @@ class IdentityTable internal constructor(context: Context?, databaseHelper: Sign """ } + fun getIdentityStoreRecord(serviceId: ServiceId?): IdentityStoreRecord? { + return if (serviceId != null) { + getIdentityStoreRecord(serviceId.toString()) + } else { + null + } + } + fun getIdentityStoreRecord(addressName: String): IdentityStoreRecord? { readableDatabase .select() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java index cc267f7205..002275d85b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java @@ -96,7 +96,7 @@ public final class MentionUtil { BodyRangeList.Builder builder = BodyRangeList.newBuilder(); for (Mention mention : mentions) { - String uuid = Recipient.resolved(mention.getRecipientId()).requireServiceId().toString(); + String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString(); builder.addRanges(BodyRangeList.BodyRange.newBuilder() .setMentionUuid(uuid) .setStart(mention.getStart()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt index f555cabf93..1bd13d5684 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -142,6 +142,7 @@ import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.isStory import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage import java.io.Closeable import java.io.IOException @@ -845,7 +846,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val threadId = threads.getOrCreateThreadIdFor(recipient) val messageId: MessageId = writableDatabase.withinTransaction { db -> val self = Recipient.self() - val markRead = joinedUuids.contains(self.requireServiceId().uuid()) || self.id == sender + val markRead = joinedUuids.contains(self.requireServiceId().rawUuid) || self.id == sender val updateDetails: ByteArray = GroupCallUpdateDetails.newBuilder() .setEraId(eraId) .setStartedCallUuid(Recipient.resolved(sender).requireServiceId().toString()) @@ -919,7 +920,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } val updateDetail = GroupCallUpdateDetailsUtil.parse(message.body) - val containsSelf = joinedUuids.contains(SignalStore.account().requireAci().uuid()) + val containsSelf = joinedUuids.contains(SignalStore.account().requireAci().rawUuid) val sameEraId = updateDetail.eraId == eraId && !Util.isEmpty(eraId) val inCallUuids = if (sameEraId) joinedUuids.map { it.toString() } else emptyList() val contentValues = contentValuesOf( @@ -954,7 +955,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat MmsReader(cursor).use { reader -> val record = reader.getNext() ?: return@withinTransaction false val groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(record.body) - val containsSelf = peekJoinedUuids.contains(SignalStore.account().requireAci().uuid()) + val containsSelf = peekJoinedUuids.contains(SignalStore.account().requireAci().rawUuid) val sameEraId = groupCallUpdateDetails.eraId == peekGroupCallEraId && !Util.isEmpty(peekGroupCallEraId) val inCallUuids = if (sameEraId) { @@ -3088,9 +3089,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val members: MutableSet = mutableSetOf() if (message.isGroupUpdate && message.isV2Group) { + // TODO [greyson][ServiceId] pending members could be ACI's or PNI's members += message.requireGroupV2Properties().allActivePendingAndRemovedMembers .distinct() - .map { uuid -> RecipientId.from(ServiceId.from(uuid)) } + .map { uuid -> RecipientId.from(ACI.from(uuid)) } .toList() members -= Recipient.self().id diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/PnpOperations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/PnpOperations.kt index 04d65abfaf..59bcfb0ec8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/PnpOperations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/PnpOperations.kt @@ -3,8 +3,9 @@ package org.thoughtcrime.securesms.database import app.cash.exhaustive.Exhaustive import org.thoughtcrime.securesms.database.model.RecipientRecord import org.thoughtcrime.securesms.recipients.RecipientId -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI /** * Encapsulates data around processing a tuple of user data into a user entry in [RecipientTable]. @@ -15,18 +16,20 @@ data class PnpDataSet( val pni: PNI?, val aci: ACI?, val byE164: RecipientId?, - val byPniSid: RecipientId?, - val byPniOnly: RecipientId?, - val byAciSid: RecipientId?, + val byPni: RecipientId?, + val byAci: RecipientId?, val e164Record: RecipientRecord? = null, - val pniSidRecord: RecipientRecord? = null, - val aciSidRecord: RecipientRecord? = null + val pniRecord: RecipientRecord? = null, + val aciRecord: RecipientRecord? = null ) { /** * @return The common id if all non-null ids are equal, or null if all are null or at least one non-null pair doesn't match. */ - val commonId: RecipientId? = findCommonId(listOf(byE164, byPniSid, byPniOnly, byAciSid)) + val commonId: RecipientId? = findCommonId(listOf(byE164, byPni, byAci)) + + /** The ID that would be used to contact this user. */ + val serviceId: ServiceId? = aci ?: pni fun MutableSet.replace(recipientId: RecipientId, update: (RecipientRecord) -> RecipientRecord) { val toUpdate = this.first { it.id == recipientId } @@ -43,7 +46,7 @@ data class PnpDataSet( return this } - val records: MutableSet = listOfNotNull(e164Record, pniSidRecord, aciSidRecord).toMutableSet() + val records: MutableSet = listOfNotNull(e164Record, pniRecord, aciRecord).toMutableSet() for (operation in operations) { @Exhaustive @@ -55,16 +58,12 @@ data class PnpDataSet( records.replace(operation.recipientId) { record -> record.copy( pni = null, - serviceId = if (record.sidIsPni()) { - null - } else { - record.serviceId - } + aci = record.aci ) } } is PnpOperation.SetAci -> { - records.replace(operation.recipientId) { it.copy(serviceId = operation.aci) } + records.replace(operation.recipientId) { it.copy(aci = operation.aci) } } is PnpOperation.SetE164 -> { records.replace(operation.recipientId) { it.copy(e164 = operation.e164) } @@ -72,12 +71,7 @@ data class PnpDataSet( is PnpOperation.SetPni -> { records.replace(operation.recipientId) { record -> record.copy( - pni = operation.pni, - serviceId = if (record.sidIsPni()) { - operation.pni - } else { - record.serviceId ?: operation.pni - } + pni = operation.pni ) } } @@ -89,7 +83,7 @@ data class PnpDataSet( primary.copy( e164 = primary.e164 ?: secondary.e164, pni = primary.pni ?: secondary.pni, - serviceId = primary.serviceId ?: secondary.serviceId + aci = primary.aci ?: secondary.aci ) } @@ -101,20 +95,16 @@ data class PnpDataSet( } val newE164Record = if (e164 != null) records.firstOrNull { it.e164 == e164 } else null - val newPniSidRecord = if (pni != null) records.firstOrNull { it.serviceId == pni } else null - val newAciSidRecord = if (aci != null) records.firstOrNull { it.serviceId == aci } else null + val newPniRecord = if (pni != null) records.firstOrNull { it.pni == pni } else null + val newAciRecord = if (aci != null) records.firstOrNull { it.aci == aci } else null - return PnpDataSet( - e164 = e164, - pni = pni, - aci = aci, + return this.copy( byE164 = newE164Record?.id, - byPniSid = newPniSidRecord?.id, - byPniOnly = byPniOnly, - byAciSid = newAciSidRecord?.id, + byPni = newPniRecord?.id, + byAci = newAciRecord?.id, e164Record = newE164Record, - pniSidRecord = newPniSidRecord, - aciSidRecord = newAciSidRecord + pniRecord = newPniRecord, + aciRecord = newAciRecord ) } 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 e8382cb85f..813a9267f1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -104,9 +104,9 @@ import org.thoughtcrime.securesms.wallpaper.ChatWallpaper import org.thoughtcrime.securesms.wallpaper.ChatWallpaperFactory import org.thoughtcrime.securesms.wallpaper.WallpaperStorage import org.whispersystems.signalservice.api.profiles.SignalServiceProfile -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.storage.SignalAccountRecord import org.whispersystems.signalservice.api.storage.SignalContactRecord @@ -134,7 +134,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da const val TABLE_NAME = "recipient" const val ID = "_id" - const val SERVICE_ID = "uuid" + const val ACI_COLUMN = "aci" const val PNI_COLUMN = "pni" const val USERNAME = "username" const val PHONE = "phone" @@ -202,7 +202,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da """ CREATE TABLE $TABLE_NAME ( $ID INTEGER PRIMARY KEY AUTOINCREMENT, - $SERVICE_ID TEXT UNIQUE DEFAULT NULL, + $ACI_COLUMN TEXT UNIQUE DEFAULT NULL, $USERNAME TEXT UNIQUE DEFAULT NULL, $PHONE TEXT UNIQUE DEFAULT NULL, $EMAIL TEXT UNIQUE DEFAULT NULL, @@ -266,12 +266,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val CREATE_INDEXS = arrayOf( "CREATE INDEX IF NOT EXISTS recipient_group_type_index ON $TABLE_NAME ($GROUP_TYPE);", "CREATE UNIQUE INDEX IF NOT EXISTS recipient_pni_index ON $TABLE_NAME ($PNI_COLUMN)", - "CREATE INDEX IF NOT EXISTS recipient_service_id_profile_key ON $TABLE_NAME ($SERVICE_ID, $PROFILE_KEY) WHERE $SERVICE_ID NOT NULL AND $PROFILE_KEY NOT NULL" + "CREATE INDEX IF NOT EXISTS recipient_service_id_profile_key ON $TABLE_NAME ($ACI_COLUMN, $PROFILE_KEY) WHERE $ACI_COLUMN NOT NULL AND $PROFILE_KEY NOT NULL" ) private val RECIPIENT_PROJECTION: Array = arrayOf( ID, - SERVICE_ID, + ACI_COLUMN, PNI_COLUMN, USERNAME, PHONE, @@ -424,17 +424,16 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } fun getByServiceId(serviceId: ServiceId): Optional { - return getByColumn(SERVICE_ID, serviceId.toString()) + return when (serviceId) { + is ACI -> getByAci(serviceId) + is PNI -> getByPni(serviceId) + } } - fun getByCallLinkRoomId(callLinkRoomId: CallLinkRoomId): Optional { - return getByColumn(CALL_LINK_ROOM_ID, callLinkRoomId.serialize()) + fun getByAci(aci: ACI): Optional { + return getByColumn(ACI_COLUMN, aci.toString()) } - /** - * Will return a recipient matching the PNI, but only in the explicit [PNI_COLUMN]. This should only be checked in conjunction with [getByServiceId] as a way - * to avoid creating a recipient we already merged. - */ fun getByPni(pni: PNI): Optional { return getByColumn(PNI_COLUMN, pni.toString()) } @@ -443,35 +442,39 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return getByColumn(USERNAME, username) } + fun getByCallLinkRoomId(callLinkRoomId: CallLinkRoomId): Optional { + return getByColumn(CALL_LINK_ROOM_ID, callLinkRoomId.serialize()) + } + fun isAssociated(serviceId: ServiceId, pni: PNI): Boolean { - return readableDatabase.exists(TABLE_NAME).where("$SERVICE_ID = ? AND $PNI_COLUMN = ?", serviceId.toString(), pni.toString()).run() + return readableDatabase.exists(TABLE_NAME).where("$ACI_COLUMN = ? AND $PNI_COLUMN = ?", serviceId.toString(), pni.toString()).run() } @JvmOverloads fun getAndPossiblyMerge(serviceId: ServiceId?, e164: String?, changeSelf: Boolean = false): RecipientId { - require(!(serviceId == null && e164 == null)) { "Must provide an ACI or E164!" } - return getAndPossiblyMerge(serviceId = serviceId, pni = null, e164 = e164, pniVerified = false, changeSelf = changeSelf) + require(serviceId != null || e164 != null) { "Must provide an ACI or E164!" } + return when (serviceId) { + is ACI -> getAndPossiblyMerge(aci = serviceId, pni = null, e164 = e164, pniVerified = false, changeSelf = changeSelf) + is PNI -> getAndPossiblyMerge(aci = null, pni = serviceId, e164 = e164, pniVerified = false, changeSelf = changeSelf) + else -> getAndPossiblyMerge(aci = null, pni = null, e164 = e164, pniVerified = false, changeSelf = changeSelf) + } } /** * Gets and merges a (serviceId, pni, e164) tuple, doing merges/updates as needed, and giving you back the final RecipientId. * It is assumed that the tuple is verified. Do not give this method an untrusted association. */ - fun getAndPossiblyMergePnpVerified(serviceId: ServiceId?, pni: PNI?, e164: String?): RecipientId { + fun getAndPossiblyMergePnpVerified(aci: ACI?, pni: PNI?, e164: String?): RecipientId { if (!FeatureFlags.phoneNumberPrivacy()) { throw AssertionError() } - return getAndPossiblyMerge(serviceId = serviceId, pni = pni, e164 = e164, pniVerified = true, changeSelf = false) + return getAndPossiblyMerge(aci = aci, pni = pni, e164 = e164, pniVerified = true, changeSelf = false) } @VisibleForTesting - fun getAndPossiblyMerge(serviceId: ServiceId?, pni: PNI?, e164: String?, pniVerified: Boolean = false, changeSelf: Boolean = false): RecipientId { - require(!(serviceId == null && e164 == null)) { "Must provide an ACI or E164!" } - - if ((serviceId is PNI) && pni != null && serviceId != pni) { - throw AssertionError("Provided two non-matching PNIs! serviceId: $serviceId, pni: $pni") - } + fun getAndPossiblyMerge(aci: ACI?, pni: PNI?, e164: String?, pniVerified: Boolean = false, changeSelf: Boolean = false): RecipientId { + require(aci != null || e164 != null) { "Must provide an ACI or E164!" } val db = writableDatabase var transactionSuccessful = false @@ -479,18 +482,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da db.beginTransaction() try { - result = when { - serviceId is ACI -> processPnpTuple(e164 = e164, pni = pni, aci = serviceId, pniVerified = pniVerified, changeSelf = changeSelf) - serviceId is PNI -> processPnpTuple(e164 = e164, pni = serviceId, aci = null, pniVerified = pniVerified, changeSelf = changeSelf) - serviceId == null -> processPnpTuple(e164 = e164, pni = pni, aci = null, pniVerified = pniVerified, changeSelf = changeSelf) - serviceId == pni -> processPnpTuple(e164 = e164, pni = pni, aci = null, pniVerified = pniVerified, changeSelf = changeSelf) - pni != null -> processPnpTuple(e164 = e164, pni = pni, aci = ACI.from(serviceId.uuid()), pniVerified = pniVerified, changeSelf = changeSelf) - getByPni(PNI.from(serviceId.uuid())).isPresent -> processPnpTuple(e164 = e164, pni = PNI.from(serviceId.uuid()), aci = null, pniVerified = pniVerified, changeSelf = changeSelf) - else -> processPnpTuple(e164 = e164, pni = pni, aci = ACI.fromNullable(serviceId), pniVerified = pniVerified, changeSelf = changeSelf) - } + result = processPnpTuple(e164 = e164, pni = pni, aci = aci, pniVerified = pniVerified, changeSelf = changeSelf) if (result.operations.isNotEmpty() || result.requiredInsert) { - Log.i(TAG, "[getAndPossiblyMerge] ($serviceId, $pni, $e164) BreadCrumbs: ${result.breadCrumbs}, Operations: ${result.operations}, RequiredInsert: ${result.requiredInsert}, FinalId: ${result.finalId}") + Log.i(TAG, "[getAndPossiblyMerge] ($aci, $pni, $e164) BreadCrumbs: ${result.breadCrumbs}, Operations: ${result.operations}, RequiredInsert: ${result.requiredInsert}, FinalId: ${result.finalId}") } db.setTransactionSuccessful() @@ -525,17 +520,17 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val serviceIdToProfileKey: MutableMap = mutableMapOf() readableDatabase - .select(SERVICE_ID, PROFILE_KEY) + .select(ACI_COLUMN, PROFILE_KEY) .from(TABLE_NAME) - .where("$SERVICE_ID NOT NULL AND $PROFILE_KEY NOT NULL") + .where("$ACI_COLUMN NOT NULL AND $PROFILE_KEY NOT NULL") .run() .use { cursor -> while (cursor.moveToNext()) { - val serviceId: ServiceId? = ServiceId.parseOrNull(cursor.requireString(SERVICE_ID)) + val aci: ACI? = ACI.parseOrNull(cursor.requireString(ACI_COLUMN)) val profileKey: ProfileKey? = ProfileKeyUtil.profileKeyOrNull(cursor.requireString(PROFILE_KEY)) - if (serviceId != null && profileKey != null) { - serviceIdToProfileKey[serviceId] = profileKey + if (aci != null && profileKey != null) { + serviceIdToProfileKey[aci] = profileKey } } } @@ -827,19 +822,19 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da if (id < 0) { Log.w(TAG, "[applyStorageSyncContactInsert] Failed to insert. Possibly merging.") if (FeatureFlags.phoneNumberPrivacy()) { - recipientId = getAndPossiblyMergePnpVerified(if (insert.serviceId.isValid) insert.serviceId else null, insert.pni.orElse(null), insert.number.orElse(null)) + recipientId = getAndPossiblyMergePnpVerified(if (insert.aci.isValid) insert.aci else null, insert.pni.orElse(null), insert.number.orElse(null)) } else { - recipientId = getAndPossiblyMerge(if (insert.serviceId.isValid) insert.serviceId else null, insert.number.orElse(null)) + recipientId = getAndPossiblyMerge(if (insert.aci.isValid) insert.aci else null, insert.number.orElse(null)) } db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId)) } else { recipientId = RecipientId.from(id) } - if (insert.identityKey.isPresent && insert.serviceId.isValid) { + if (insert.identityKey.isPresent && insert.aci.isValid) { try { val identityKey = IdentityKey(insert.identityKey.get(), 0) - identities.updateIdentityAfterSync(insert.serviceId.toString(), recipientId, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(insert.identityState)) + identities.updateIdentityAfterSync(insert.aci.toString(), recipientId, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(insert.identityState)) } catch (e: InvalidKeyException) { Log.w(TAG, "Failed to process identity key during insert! Skipping.", e) } @@ -868,9 +863,9 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da Log.w(TAG, "[applyStorageSyncContactUpdate] Found user $recipientId. Possibly merging.") if (FeatureFlags.phoneNumberPrivacy()) { - recipientId = getAndPossiblyMergePnpVerified(if (update.new.serviceId.isValid) update.new.serviceId else null, update.new.pni.orElse(null), update.new.number.orElse(null)) + recipientId = getAndPossiblyMergePnpVerified(if (update.new.aci.isValid) update.new.aci else null, update.new.pni.orElse(null), update.new.number.orElse(null)) } else { - recipientId = getAndPossiblyMerge(if (update.new.serviceId.isValid) update.new.serviceId else null, update.new.number.orElse(null)) + recipientId = getAndPossiblyMerge(if (update.new.aci.isValid) update.new.aci else null, update.new.number.orElse(null)) } Log.w(TAG, "[applyStorageSyncContactUpdate] Merged into $recipientId") @@ -887,9 +882,9 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da try { val oldIdentityRecord = identityStore.getIdentityRecord(recipientId) - if (update.new.identityKey.isPresent && update.new.serviceId.isValid) { + if (update.new.identityKey.isPresent && update.new.aci.isValid) { val identityKey = IdentityKey(update.new.identityKey.get(), 0) - identities.updateIdentityAfterSync(update.new.serviceId.toString(), recipientId, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(update.new.identityState)) + identities.updateIdentityAfterSync(update.new.aci.toString(), recipientId, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(update.new.identityState)) } val newIdentityRecord = identityStore.getIdentityRecord(recipientId) @@ -1108,7 +1103,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da private fun getRecordForSync(query: String?, args: Array?): List { val table = """ - $TABLE_NAME LEFT OUTER JOIN ${IdentityTable.TABLE_NAME} ON $TABLE_NAME.$SERVICE_ID = ${IdentityTable.TABLE_NAME}.${IdentityTable.ADDRESS} + $TABLE_NAME LEFT OUTER JOIN ${IdentityTable.TABLE_NAME} ON $TABLE_NAME.$ACI_COLUMN = ${IdentityTable.TABLE_NAME}.${IdentityTable.ADDRESS} LEFT OUTER JOIN ${GroupTable.TABLE_NAME} ON $TABLE_NAME.$GROUP_ID = ${GroupTable.TABLE_NAME}.${GroupTable.GROUP_ID} LEFT OUTER JOIN ${ThreadTable.TABLE_NAME} ON $TABLE_NAME.$ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} """ @@ -1152,7 +1147,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .where( """ $STORAGE_SERVICE_ID NOT NULL AND ( - ($GROUP_TYPE = ? AND $SERVICE_ID NOT NULL AND $ID != ?) + ($GROUP_TYPE = ? AND $ACI_COLUMN NOT NULL AND $ID != ?) OR $GROUP_TYPE = ? OR @@ -2004,7 +1999,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da Log.w(TAG, "[setPhoneNumber] Hit a conflict when trying to update $id. Possibly merging.") val existing: RecipientRecord = getRecord(id) - val newId = getAndPossiblyMerge(existing.serviceId, e164) + val newId = getAndPossiblyMerge(existing.aci, e164) Log.w(TAG, "[setPhoneNumber] Resulting id: $newId") db.setTransactionSuccessful() @@ -2054,7 +2049,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da * Associates the provided IDs together. The assumption here is that all of the IDs correspond to the local user and have been verified. */ fun linkIdsForSelf(aci: ACI, pni: PNI, e164: String) { - val id: RecipientId = getAndPossiblyMerge(serviceId = aci, pni = pni, e164 = e164, changeSelf = true, pniVerified = true) + val id: RecipientId = getAndPossiblyMerge(aci = aci, pni = pni, e164 = e164, changeSelf = true, pniVerified = true) updatePendingSelfData(id) } @@ -2067,7 +2062,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da db.beginTransaction() try { val id = Recipient.self().id - val newId = getAndPossiblyMerge(serviceId = SignalStore.account().requireAci(), pni = pni, e164 = e164, pniVerified = true, changeSelf = true) + val newId = getAndPossiblyMerge(aci = SignalStore.account().requireAci(), pni = pni, e164 = e164, pniVerified = true, changeSelf = true) if (id == newId) { Log.i(TAG, "[updateSelfPhone] Phone updated for self") @@ -2170,8 +2165,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da fun setPni(id: RecipientId, pni: PNI) { writableDatabase .update(TABLE_NAME) - .values(SERVICE_ID to pni.toString()) - .where("$ID = ? AND ($SERVICE_ID IS NULL OR $SERVICE_ID = $PNI_COLUMN)", id) + .values(ACI_COLUMN to pni.toString()) + .where("$ID = ? AND ($ACI_COLUMN IS NULL OR $ACI_COLUMN = $PNI_COLUMN)", id) .run() writableDatabase @@ -2212,7 +2207,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da fun markRegisteredOrThrow(id: RecipientId, serviceId: ServiceId) { val contentValues = contentValuesOf( REGISTERED to RegisteredState.REGISTERED.id, - SERVICE_ID to serviceId.toString().lowercase(), + ACI_COLUMN to serviceId.toString().lowercase(), UNREGISTERED_TIMESTAMP to 0 ) if (update(id, contentValues)) { @@ -2226,7 +2221,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da if (FeatureFlags.phoneNumberPrivacy()) { val record = getRecord(id) - if (record.pni != null && record.serviceId != record.pni) { + if (record.aci != null && record.pni != null) { markUnregisteredAndSplit(id, record) } else { markUnregisteredWithoutSplit(id) @@ -2241,7 +2236,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da * This is to allow a new user to register the number with a new ACI. */ private fun markUnregisteredAndSplit(id: RecipientId, record: RecipientRecord) { - check(record.pni != null && record.pni != record.serviceId) + check(record.aci != null && record.pni != null) val contentValues = contentValuesOf( REGISTERED to RegisteredState.NOT_REGISTERED.id, @@ -2256,7 +2251,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(id) } - val splitId = getAndPossiblyMerge(record.pni, record.pni, record.e164) + val splitId = getAndPossiblyMerge(null, record.pni, record.e164) Log.i(TAG, "Split off new recipient as $splitId (ACI-only recipient is $id)") } @@ -2284,7 +2279,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da check(FeatureFlags.phoneNumberPrivacy()) val record = getByStorageId(storageId)!! - check(record.serviceId != null && record.pni != null && record.serviceId != record.pni) + check(record.aci != null && record.pni != null) writableDatabase .update(TABLE_NAME) @@ -2295,7 +2290,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .where("$ID = ?", record.id) .run() - getAndPossiblyMerge(record.pni, record.pni, record.e164) + getAndPossiblyMerge(null, record.pni, record.e164) } fun bulkUpdatedRegisteredStatus(registered: Map, unregistered: Collection) { @@ -2308,7 +2303,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da put(REGISTERED, RegisteredState.REGISTERED.id) put(UNREGISTERED_TIMESTAMP, 0) if (serviceId != null) { - put(SERVICE_ID, serviceId.toString().lowercase()) + put(ACI_COLUMN, serviceId.toString().lowercase()) } } @@ -2344,12 +2339,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da db.beginTransaction() try { for ((e164, aci) in mapping) { - var aciEntry = if (aci != null) getByServiceId(aci) else Optional.empty() + var aciEntry = if (aci != null) getByAci(aci) else Optional.empty() if (aciEntry.isPresent) { val idChanged = setPhoneNumber(aciEntry.get(), e164) if (idChanged) { - aciEntry = getByServiceId(aci!!) + aciEntry = getByAci(aci!!) } } @@ -2380,7 +2375,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da db.beginTransaction() try { for ((e164, result) in mapping) { - ids += getAndPossiblyMerge(serviceId = result.aci, pni = result.pni, e164 = e164, pniVerified = false, changeSelf = false) + ids += getAndPossiblyMerge(aci = result.aci, pni = result.pni, e164 = e164, pniVerified = false, changeSelf = false) } db.setTransactionSuccessful() @@ -2492,12 +2487,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da .run() } is PnpOperation.RemovePni -> { - writableDatabase - .update(TABLE_NAME) - .values(SERVICE_ID to null) - .where("$ID = ? AND $SERVICE_ID NOT NULL AND $SERVICE_ID = $PNI_COLUMN", operation.recipientId) - .run() - writableDatabase .update(TABLE_NAME) .values(PNI_COLUMN to null) @@ -2508,7 +2497,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da writableDatabase .update(TABLE_NAME) .values( - SERVICE_ID to operation.aci.toString(), + ACI_COLUMN to operation.aci.toString(), REGISTERED to RegisteredState.REGISTERED.id, UNREGISTERED_TIMESTAMP to 0 ) @@ -2525,8 +2514,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da is PnpOperation.SetPni -> { writableDatabase .update(TABLE_NAME) - .values(SERVICE_ID to operation.pni.toString()) - .where("$ID = ? AND ($SERVICE_ID IS NULL OR $SERVICE_ID = $PNI_COLUMN)", operation.recipientId) + .values(ACI_COLUMN to operation.pni.toString()) + .where("$ID = ? AND ($ACI_COLUMN IS NULL OR $ACI_COLUMN = $PNI_COLUMN)", operation.recipientId) .run() writableDatabase @@ -2596,9 +2585,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da pni = pni, aci = aci, byE164 = e164?.let { getByE164(it).orElse(null) }, - byPniSid = pni?.let { getByServiceId(it).orElse(null) }, - byPniOnly = pni?.let { getByPni(it).orElse(null) }, - byAciSid = aci?.let { getByServiceId(it).orElse(null) } + byPni = pni?.let { getByPni(it).orElse(null) }, + byAci = aci?.let { getByAci(it).orElse(null) } ) val allRequiredDbFields: MutableList = mutableListOf() @@ -2606,13 +2594,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da allRequiredDbFields += partialData.byE164 } if (aci != null) { - allRequiredDbFields += partialData.byAciSid + allRequiredDbFields += partialData.byAci } if (pni != null) { - allRequiredDbFields += partialData.byPniOnly - } - if (pni != null && aci == null) { - allRequiredDbFields += partialData.byPniSid + allRequiredDbFields += partialData.byPni } val allRequiredDbFieldPopulated: Boolean = allRequiredDbFields.all { it != null } @@ -2630,7 +2615,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } // Nothing matches - if (partialData.byE164 == null && partialData.byPniSid == null && partialData.byAciSid == null) { + if (partialData.byE164 == null && partialData.byPni == null && partialData.byAci == null) { breadCrumbs += "NothingMatches" return PnpChangeSet( id = PnpIdResolver.PnpInsert( @@ -2642,8 +2627,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ) } - // TODO pni only record? - // At this point, we know that records have been found for at least two of the fields, // and that there are at least two unique IDs among the records. // @@ -2653,40 +2636,40 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da breadCrumbs += "NeedsMerge" - val fullData = partialData.copy( + val preMergeData = partialData.copy( e164Record = partialData.byE164?.let { getRecord(it) }, - pniSidRecord = partialData.byPniSid?.let { getRecord(it) }, - aciSidRecord = partialData.byAciSid?.let { getRecord(it) } + pniRecord = partialData.byPni?.let { getRecord(it) }, + aciRecord = partialData.byAci?.let { getRecord(it) } ) - check(fullData.commonId == null) - check(listOfNotNull(fullData.byE164, fullData.byPniSid, fullData.byPniOnly, fullData.byAciSid).size >= 2) + check(preMergeData.commonId == null) + check(listOfNotNull(preMergeData.byE164, preMergeData.byPni, preMergeData.byAci).size >= 2) val operations: LinkedHashSet = linkedSetOf() - operations += processPossibleE164PniSidMerge(pni, pniVerified, fullData, breadCrumbs) - operations += processPossiblePniSidAciSidMerge(e164, pni, aci, fullData.perform(operations), changeSelf, breadCrumbs) - operations += processPossibleE164AciSidMerge(e164, pni, aci, fullData.perform(operations), changeSelf, breadCrumbs) + operations += processPossibleE164PniMerge(preMergeData, pniVerified, changeSelf, breadCrumbs) + operations += processPossiblePniAciMerge(preMergeData.perform(operations), pniVerified, changeSelf, breadCrumbs) + operations += processPossibleE164AciMerge(preMergeData.perform(operations), pniVerified, changeSelf, breadCrumbs) - val finalData: PnpDataSet = fullData.perform(operations) - val primaryId: RecipientId = listOfNotNull(finalData.byAciSid, finalData.byE164, finalData.byPniSid).first() + val postMergeData: PnpDataSet = preMergeData.perform(operations) + val primaryId: RecipientId = listOfNotNull(postMergeData.byAci, postMergeData.byE164, postMergeData.byPni).first() - if (finalData.byAciSid == null && aci != null) { + if (postMergeData.byAci == null && aci != null) { breadCrumbs += "FinalUpdateAci" operations += PnpOperation.SetAci( recipientId = primaryId, aci = aci ) - if (!pniVerified && finalData.pni != null && sessions.hasAnySessionFor(finalData.pni.toString())) { + if (!pniVerified && postMergeData.pni != null && sessions.hasAnySessionFor(postMergeData.pni.toString())) { operations += PnpOperation.SessionSwitchoverInsert( recipientId = primaryId, - e164 = finalData.e164 + e164 = postMergeData.e164 ) } } - if (finalData.byE164 == null && e164 != null && (changeSelf || notSelf(e164, pni, aci))) { + if (postMergeData.byE164 == null && e164 != null && (changeSelf || notSelf(e164, pni, aci))) { breadCrumbs += "FinalUpdateE164" operations += PnpOperation.SetE164( recipientId = primaryId, @@ -2694,7 +2677,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ) } - if (finalData.byPniSid == null && finalData.byPniOnly == null && pni != null) { + if (postMergeData.byPni == null && pni != null) { breadCrumbs += "FinalUpdatePni" operations += PnpOperation.SetPni( recipientId = primaryId, @@ -2702,12 +2685,14 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ) } - if (!pniVerified && fullData.pniSidRecord != null && finalData.aciSidRecord != null && sessions.hasAnySessionFor(fullData.pniSidRecord.serviceId.toString())) { + val preSseOperationCount = operations.size + + operations += sessionSwitchoverEventIfNeeded(pniVerified, preMergeData.e164Record, postMergeData.e164Record) + operations += sessionSwitchoverEventIfNeeded(pniVerified, preMergeData.pniRecord, postMergeData.pniRecord) + operations += sessionSwitchoverEventIfNeeded(pniVerified, preMergeData.aciRecord, postMergeData.aciRecord) + + if (operations.size > preSseOperationCount) { breadCrumbs += "FinalUpdateSSE" - operations += PnpOperation.SessionSwitchoverInsert( - recipientId = primaryId, - e164 = finalData.e164 - ) } return PnpChangeSet( @@ -2717,12 +2702,51 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ) } + /** + * A session switchover event indicates a situation where we start communicating with a different session that we were before. + * If a switchover is "verified" (i.e. proven safe cryptographically by the sender), then this doesn't require a user-visible event. + * But if it's not verified and we're switching from one established session to another, the user needs to be aware. + */ + private fun needsSessionSwitchoverEvent(pniVerified: Boolean, oldServiceId: ServiceId?, newServiceId: ServiceId?): Boolean { + return !pniVerified && + oldServiceId != null && + newServiceId != null && + oldServiceId != newServiceId && + sessions.hasAnySessionFor(oldServiceId.toString()) && + identities.getIdentityStoreRecord(oldServiceId)?.identityKey != identities.getIdentityStoreRecord(newServiceId)?.identityKey + } + + /** + * For details on SSE's, see [needsSessionSwitchoverEvent]. This method is just a helper around comparing service ID's from two + * records and turning it into a possible event. + */ + private fun sessionSwitchoverEventIfNeeded(pniVerified: Boolean, oldRecord: RecipientRecord?, newRecord: RecipientRecord?): List { + return if (oldRecord != null && newRecord != null && needsSessionSwitchoverEvent(pniVerified, oldRecord.serviceId, newRecord.serviceId)) { + listOf( + PnpOperation.SessionSwitchoverInsert( + recipientId = newRecord.id, + e164 = newRecord.e164 + ) + ) + } else { + emptyList() + } + } + + private fun notSelf(data: PnpDataSet): Boolean { + return notSelf(data.e164, data.pni, data.aci) + } + private fun notSelf(e164: String?, pni: PNI?, aci: ACI?): Boolean { return (e164 == null || e164 != SignalStore.account().e164) && (pni == null || pni != SignalStore.account().pni) && (aci == null || aci != SignalStore.account().aci) } + private fun isSelf(data: PnpDataSet): Boolean { + return isSelf(data.e164, data.pni, data.aci) + } + private fun isSelf(e164: String?, pni: PNI?, aci: ACI?): Boolean { return (e164 != null && e164 == SignalStore.account().e164) || (pni != null && pni == SignalStore.account().pni) || @@ -2735,7 +2759,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val operations: LinkedHashSet = linkedSetOf() // This is a special case. The ACI passed in doesn't match the common record. We can't change ACIs, so we need to make a new record. - if (aci != null && aci != record.serviceId && record.serviceId != null && !record.sidIsPni()) { + if (aci != null && aci != record.aci && record.aci != null) { breadCrumbs += "AciDoesNotMatchCommonRecord" if (record.e164 == e164 && (changeSelf || notSelf(e164, pni, aci))) { @@ -2773,7 +2797,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ) } - if (aci != null && record.serviceId != aci) { + if (aci != null && record.aci != aci) { operations += PnpOperation.SetAci( recipientId = commonId, aci = aci @@ -2788,9 +2812,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ) } - val newServiceId: ServiceId? = aci ?: pni ?: record.serviceId + val oldServiceId: ServiceId? = record.aci ?: record.pni + val newServiceId: ServiceId? = aci ?: pni ?: oldServiceId - if (!pniVerified && record.serviceId != null && record.serviceId != newServiceId && sessions.hasAnySessionFor(record.serviceId.toString())) { + if (!pniVerified && newServiceId != oldServiceId && oldServiceId != null && sessions.hasAnySessionFor(oldServiceId.toString())) { operations += PnpOperation.SessionSwitchoverInsert(recipientId = commonId, e164 = record.e164 ?: e164) } @@ -2801,133 +2826,180 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da ) } - private fun processPossibleE164PniSidMerge(pni: PNI?, pniVerified: Boolean, data: PnpDataSet, breadCrumbs: MutableList): LinkedHashSet { - if (pni == null || data.byE164 == null || data.byPniSid == null || data.e164Record == null || data.pniSidRecord == null || data.e164Record.id == data.pniSidRecord.id) { + /** + * Resolves any possible E164-PNI conflicts/merges. In these situations, the E164-based row is more dominant + * and can "steal" data from PNI-based rows, or merge PNI-based rows into itself. + * + * We do have to be careful when merging/stealing data to leave possible ACI's that could be on the PNI + * row alone: remember, ACI's are forever-bound to a given RecipientId. + */ + private fun processPossibleE164PniMerge(data: PnpDataSet, pniVerified: Boolean, changeSelf: Boolean, breadCrumbs: MutableList): LinkedHashSet { + // Filter to ensure that we're only looking at situations where a PNI and E164 record both exist but do not match + if (data.pni == null || data.byPni == null || data.pniRecord == null || data.e164 == null || data.byE164 == null || data.e164Record == null || data.e164Record.id == data.pniRecord.id) { return linkedSetOf() } // We have found records for both the E164 and PNI, and they're different - breadCrumbs += "E164PniSidMerge" + breadCrumbs += "E164PniMerge" + + if (!changeSelf && isSelf(data)) { + breadCrumbs += "ChangeSelfPreventsE164PniMerge" + return linkedSetOf() + } val operations: LinkedHashSet = linkedSetOf() - // The PNI record only has a single identifier. We know we must merge. - if (data.pniSidRecord.sidOnly(pni)) { + if (data.pniRecord.pniOnly()) { + // The PNI record only has a single identifier. We know we must merge. breadCrumbs += "PniOnly" if (data.e164Record.pni != null) { + // The e164 record we're merging into has a PNI already. This means that we've entered an 'unstable PNI mapping' scenario. + // This isn't expected, but we need to handle it gracefully and merge the two rows together. operations += PnpOperation.RemovePni(data.byE164) + + if (needsSessionSwitchoverEvent(pniVerified, data.e164Record.pni, data.pni)) { + breadCrumbs += "E164IdentityMismatchesPniIdentity" + operations += PnpOperation.SessionSwitchoverInsert(data.byE164, data.e164) + } } operations += PnpOperation.Merge( primaryId = data.byE164, - secondaryId = data.byPniSid + secondaryId = data.byPni ) - - // TODO: Possible session switchover? } else { - check(!data.pniSidRecord.pniAndAci() && data.pniSidRecord.e164 != null) + // The record we're taking data from also has either an ACI or e164, so we need to leave that data behind - breadCrumbs += "PniSidRecordHasE164" - - operations += PnpOperation.RemovePni(data.byPniSid) - operations += PnpOperation.SetPni( - recipientId = data.byE164, - pni = pni - ) - - if (!pniVerified && sessions.hasAnySessionFor(data.pniSidRecord.serviceId.toString())) { - operations += PnpOperation.SessionSwitchoverInsert(recipientId = data.byPniSid, e164 = data.pniSidRecord.e164) - - if (data.e164Record.serviceId == null || data.e164Record.sidIsPni()) { - operations += PnpOperation.SessionSwitchoverInsert(recipientId = data.byE164, e164 = data.e164Record.e164) - } + breadCrumbs += if (data.pniRecord.aci != null && data.pniRecord.e164 != null) { + "PniRecordHasE164AndAci" + } else if (data.pniRecord.aci != null) { + "PniRecordHasAci" + } else { + "PniRecordHasE164" } - if (!pniVerified && data.e164Record.serviceId != null && data.e164Record.sidIsPni() && sessions.hasAnySessionFor(data.e164Record.serviceId.toString())) { - operations += PnpOperation.SessionSwitchoverInsert(recipientId = data.byE164, e164 = data.e164) + // Move the PNI from the PNI record to the e164 record + operations += PnpOperation.RemovePni(data.byPni) + operations += PnpOperation.SetPni( + recipientId = data.byE164, + pni = data.pni + ) + + // By migrating the PNI to the e164 record, we may cause an SSE + if (needsSessionSwitchoverEvent(pniVerified, data.e164Record.serviceId, data.e164Record.aci ?: data.pni)) { + operations += PnpOperation.SessionSwitchoverInsert(recipientId = data.byE164, e164 = data.e164Record.e164) + } + + // This is a defensive move where we put an SSE in the session we stole the PNI from and where we're moving it to in order + // to avoid a multi-step PNI swap. You could imagine that we might remove the PNI in this function call, but then add one back + // in the next function call, and each step on it's own would think that no SSE is necessary. Given that this scenario only + // happens with an unstable PNI-E164 mapping, we get out ahead of it by putting an SSE in both preemptively. + if (!pniVerified && data.pniRecord.aci == null && sessions.hasAnySessionFor(data.pni.toString())) { + operations += PnpOperation.SessionSwitchoverInsert(recipientId = data.byPni, e164 = data.pniRecord.e164) + + if (data.e164Record.aci == null) { + operations += PnpOperation.SessionSwitchoverInsert(recipientId = data.byE164, e164 = data.e164Record.e164) + } } } return operations } - private fun processPossiblePniSidAciSidMerge(e164: String?, pni: PNI?, aci: ACI?, data: PnpDataSet, changeSelf: Boolean, breadCrumbs: MutableList): LinkedHashSet { - if (pni == null || aci == null || data.byPniSid == null || data.byAciSid == null || data.pniSidRecord == null || data.aciSidRecord == null || data.pniSidRecord.id == data.aciSidRecord.id) { - return linkedSetOf() - } - - if (!changeSelf && isSelf(e164, pni, aci)) { - breadCrumbs += "ChangeSelfPreventsPniSidAciSidMerge" + /** + * Resolves any possible PNI-ACI conflicts/merges. In these situations, the ACI-based row is more dominant + * and can "steal" data from PNI-based rows, or merge PNI-based rows into itself. + */ + private fun processPossiblePniAciMerge(data: PnpDataSet, pniVerified: Boolean, changeSelf: Boolean, breadCrumbs: MutableList): LinkedHashSet { + // Filter to ensure that we're only looking at situations where a PNI and ACI record both exist but do not match + if (data.pni == null || data.byPni == null || data.pniRecord == null || data.aci == null || data.byAci == null || data.aciRecord == null || data.pniRecord.id == data.aciRecord.id) { return linkedSetOf() } // We have found records for both the PNI and ACI, and they're different - breadCrumbs += "PniSidAciSidMerge" + breadCrumbs += "PniAciMerge" + + if (!changeSelf && isSelf(data)) { + breadCrumbs += "ChangeSelfPreventsPniAciMerge" + return linkedSetOf() + } val operations: LinkedHashSet = linkedSetOf() // The PNI record only has a single identifier. We know we must merge. - if (data.pniSidRecord.sidOnly(pni)) { + if (data.pniRecord.pniOnly()) { breadCrumbs += "PniOnly" - if (data.aciSidRecord.pni != null) { - operations += PnpOperation.RemovePni(data.byAciSid) + if (data.aciRecord.pni != null) { + operations += PnpOperation.RemovePni(data.byAci) } operations += PnpOperation.Merge( - primaryId = data.byAciSid, - secondaryId = data.byPniSid + primaryId = data.byAci, + secondaryId = data.byPni ) - } else if (data.pniSidRecord.e164 == e164) { - // The PNI record also has the E164 on it. We're going to be stealing both fields, + } else if (data.pniRecord.aci == null && data.pniRecord.e164 == data.e164) { + // The PNI record also has the E164 on it with no ACI. We're going to be stealing all of it's fields, // so this is basically a merge with a little bit of extra prep. - breadCrumbs += "PniSidRecordHasMatchingE164" + breadCrumbs += "PniRecordHasMatchingE164AndNoAci" - if (data.aciSidRecord.pni != null) { - operations += PnpOperation.RemovePni(data.byAciSid) + if (data.aciRecord.pni != null) { + operations += PnpOperation.RemovePni(data.byAci) } - if (data.aciSidRecord.e164 != null && data.aciSidRecord.e164 != e164) { - operations += PnpOperation.RemoveE164(data.byAciSid) + if (data.aciRecord.e164 != null && data.aciRecord.e164 != data.e164) { + operations += PnpOperation.RemoveE164(data.byAci) + + // This also becomes a change number event + if (notSelf(data) && !data.aciRecord.isBlocked) { + operations += PnpOperation.ChangeNumberInsert( + recipientId = data.byAci, + oldE164 = data.aciRecord.e164, + newE164 = data.e164!! + ) + } } operations += PnpOperation.Merge( - primaryId = data.byAciSid, - secondaryId = data.byPniSid + primaryId = data.byAci, + secondaryId = data.byPni + ) + } else { + // The PNI record either has an ACI or a non-matching e164, meaning we need to steal what we need and leave the rest behind + + breadCrumbs += if (data.pniRecord.aci != null && data.pniRecord.e164 != data.e164) { + "PniRecordHasAciAndNonMatchingE164" + } else if (data.pniRecord.aci != null) { + "PniRecordHasAci" + } else { + "PniRecordHasNonMatchingE164" + } + + operations += PnpOperation.RemovePni(data.byPni) + + operations += PnpOperation.SetPni( + recipientId = data.byAci, + pni = data.pni ) - if (data.aciSidRecord.e164 != null && data.aciSidRecord.e164 != e164 && notSelf(e164, pni, aci) && !data.aciSidRecord.isBlocked) { - operations += PnpOperation.ChangeNumberInsert( - recipientId = data.byAciSid, - oldE164 = data.aciSidRecord.e164, - newE164 = e164!! - ) - } - } else { - check(data.pniSidRecord.e164 != null && data.pniSidRecord.e164 != e164) - breadCrumbs += "PniSidRecordHasNonMatchingE164" + if (data.e164 != null && data.aciRecord.e164 != data.e164) { + if (data.pniRecord.e164 == data.e164) { + operations += PnpOperation.RemoveE164( + recipientId = data.byPni + ) + } - operations += PnpOperation.RemovePni(data.byPniSid) - - if (data.aciSidRecord.pni != pni) { - operations += PnpOperation.SetPni( - recipientId = data.byAciSid, - pni = pni - ) - } - - if (e164 != null && data.aciSidRecord.e164 != e164) { operations += PnpOperation.SetE164( - recipientId = data.byAciSid, - e164 = e164 + recipientId = data.byAci, + e164 = data.e164 ) - if (data.aciSidRecord.e164 != null && notSelf(e164, pni, aci) && !data.aciSidRecord.isBlocked) { + if (data.aciRecord.e164 != null && notSelf(data) && !data.aciRecord.isBlocked) { operations += PnpOperation.ChangeNumberInsert( - recipientId = data.byAciSid, - oldE164 = data.aciSidRecord.e164, - newE164 = e164 + recipientId = data.byAci, + oldE164 = data.aciRecord.e164, + newE164 = data.e164 ) } } @@ -2936,18 +3008,23 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return operations } - private fun processPossibleE164AciSidMerge(e164: String?, pni: PNI?, aci: ACI?, data: PnpDataSet, changeSelf: Boolean, breadCrumbs: MutableList): List { - if (e164 == null || aci == null || data.byE164 == null || data.byAciSid == null || data.e164Record == null || data.aciSidRecord == null || data.e164Record.id == data.aciSidRecord.id) { - return emptyList() - } - - if (!changeSelf && isSelf(e164, pni, aci)) { - breadCrumbs += "ChangeSelfPreventsE164AciSidMerge" + /** + * Resolves any possible E164-ACI conflicts/merges. In these situations, the ACI-based row is more dominant + * and can "steal" data from E164-based rows, or merge E164-based rows into itself. + */ + private fun processPossibleE164AciMerge(data: PnpDataSet, pniVerified: Boolean, changeSelf: Boolean, breadCrumbs: MutableList): List { + // Filter to ensure that we're only looking at situations where a E164 and ACI record both exist but do not match + if (data.e164 == null || data.byE164 == null || data.e164Record == null || data.aci == null || data.byAci == null || data.aciRecord == null || data.e164Record.id == data.aciRecord.id) { return emptyList() } // We have found records for both the E164 and ACI, and they're different - breadCrumbs += "E164AciSidMerge" + breadCrumbs += "E164AciMerge" + + if (!changeSelf && isSelf(data)) { + breadCrumbs += "ChangeSelfPreventsE164AciMerge" + return emptyList() + } val operations: MutableList = mutableListOf() @@ -2955,63 +3032,63 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da if (data.e164Record.e164Only()) { breadCrumbs += "E164Only" - if (data.aciSidRecord.e164 != null && data.aciSidRecord.e164 != e164) { - operations += PnpOperation.RemoveE164(data.byAciSid) + if (data.aciRecord.e164 != null && data.aciRecord.e164 != data.e164) { + operations += PnpOperation.RemoveE164(data.byAci) } operations += PnpOperation.Merge( - primaryId = data.byAciSid, + primaryId = data.byAci, secondaryId = data.byE164 ) - if (data.aciSidRecord.e164 != null && data.aciSidRecord.e164 != e164 && notSelf(e164, pni, aci) && !data.aciSidRecord.isBlocked) { + if (data.aciRecord.e164 != null && data.aciRecord.e164 != data.e164 && notSelf(data) && !data.aciRecord.isBlocked) { operations += PnpOperation.ChangeNumberInsert( - recipientId = data.byAciSid, - oldE164 = data.aciSidRecord.e164, - newE164 = e164 + recipientId = data.byAci, + oldE164 = data.aciRecord.e164, + newE164 = data.e164 ) } - } else if (data.e164Record.pni != null && data.e164Record.pni == pni) { + } else if (data.e164Record.pni != null && data.e164Record.pni == data.pni) { // The E164 record also has the PNI on it. We're going to be stealing both fields, // so this is basically a merge with a little bit of extra prep. breadCrumbs += "E164RecordHasMatchingPni" - if (data.aciSidRecord.pni != null) { - operations += PnpOperation.RemovePni(data.byAciSid) + if (data.aciRecord.pni != null) { + operations += PnpOperation.RemovePni(data.byAci) } - if (data.aciSidRecord.e164 != null && data.aciSidRecord.e164 != e164) { - operations += PnpOperation.RemoveE164(data.byAciSid) + if (data.aciRecord.e164 != null && data.aciRecord.e164 != data.e164) { + operations += PnpOperation.RemoveE164(data.byAci) } operations += PnpOperation.Merge( - primaryId = data.byAciSid, + primaryId = data.byAci, secondaryId = data.byE164 ) - if (data.aciSidRecord.e164 != null && data.aciSidRecord.e164 != e164 && notSelf(e164, pni, aci) && !data.aciSidRecord.isBlocked) { + if (data.aciRecord.e164 != null && data.aciRecord.e164 != data.e164 && notSelf(data) && !data.aciRecord.isBlocked) { operations += PnpOperation.ChangeNumberInsert( - recipientId = data.byAciSid, - oldE164 = data.aciSidRecord.e164, - newE164 = e164 + recipientId = data.byAci, + oldE164 = data.aciRecord.e164, + newE164 = data.e164 ) } } else { - check(data.e164Record.pni == null || data.e164Record.pni != pni) + check(data.e164Record.pni == null || data.e164Record.pni != data.pni) breadCrumbs += "E164RecordHasNonMatchingPni" operations += PnpOperation.RemoveE164(data.byE164) operations += PnpOperation.SetE164( - recipientId = data.byAciSid, - e164 = e164 + recipientId = data.byAci, + e164 = data.e164 ) - if (data.aciSidRecord.e164 != null && data.aciSidRecord.e164 != e164 && notSelf(e164, pni, aci) && !data.aciSidRecord.isBlocked) { + if (data.aciRecord.e164 != null && data.aciRecord.e164 != data.e164 && notSelf(data) && !data.aciRecord.isBlocked) { operations += PnpOperation.ChangeNumberInsert( - recipientId = data.byAciSid, - oldE164 = data.aciSidRecord.e164, - newE164 = e164 + recipientId = data.byAci, + oldE164 = data.aciRecord.e164, + newE164 = data.e164 ) } } @@ -3047,7 +3124,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return readableDatabase .select(ID) .from(TABLE_NAME) - .where("$REGISTERED = ? and $HIDDEN = ? AND $SERVICE_ID NOT NULL", 1, 0) + .where("$REGISTERED = ? and $HIDDEN = ? AND $ACI_COLUMN NOT NULL", 1, 0) .run() .readToSet { cursor -> RecipientId.from(cursor.requireLong(ID)) @@ -3151,7 +3228,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return readableDatabase .select() .from(TABLE_NAME) - .where("$ID LIKE ? OR $SERVICE_ID LIKE ? OR $PNI_COLUMN LIKE ?", "%$query%", "%$query%", "%$query%") + .where("$ID LIKE ? OR $ACI_COLUMN LIKE ? OR $PNI_COLUMN LIKE ?", "%$query%", "%$query%", "%$query%") .run() .readToList { cursor -> getRecord(context, cursor) @@ -3482,7 +3559,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } for (uuid in blockedUuid) { - db.update(TABLE_NAME, setBlocked, "$SERVICE_ID = ?", arrayOf(uuid)) + db.update(TABLE_NAME, setBlocked, "$ACI_COLUMN = ?", arrayOf(uuid)) } val groupIdStrings: MutableList = ArrayList(groupIds.size) @@ -3810,7 +3887,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val uuidValues = contentValuesOf( PHONE to (secondaryRecord.e164 ?: primaryRecord.e164), - SERVICE_ID to (primaryRecord.serviceId ?: secondaryRecord.serviceId)?.toString(), + ACI_COLUMN to (primaryRecord.aci ?: secondaryRecord.aci)?.toString(), PNI_COLUMN to (newPni ?: secondaryRecord.pni ?: primaryRecord.pni)?.toString(), BLOCKED to (secondaryRecord.isBlocked || primaryRecord.isBlocked), MESSAGE_RINGTONE to Optional.ofNullable(primaryRecord.messageRingtone).or(Optional.ofNullable(secondaryRecord.messageRingtone)).map { obj: Uri? -> obj.toString() }.orElse(null), @@ -3862,13 +3939,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da private fun buildContentValuesForNewUser(e164: String?, pni: PNI?, aci: ACI?): ContentValues { check(e164 != null || pni != null || aci != null) { "Must provide some sort of identifier!" } - val serviceId = (aci ?: pni)?.toString() val values = contentValuesOf( PHONE to e164, - SERVICE_ID to serviceId, + ACI_COLUMN to aci?.toString(), PNI_COLUMN to pni?.toString(), STORAGE_SERVICE_ID to Base64.encodeBytes(StorageSyncHelper.generateKey()), - AVATAR_COLOR to AvatarColorHash.forAddress(serviceId, e164).serialize() + AVATAR_COLOR to AvatarColorHash.forAddress((aci ?: pni)?.toString(), e164).serialize() ) if (pni != null || aci != null) { @@ -3885,8 +3961,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da val systemName = ProfileName.fromParts(contact.systemGivenName.orElse(null), contact.systemFamilyName.orElse(null)) val username = contact.username.orElse(null) - if (contact.serviceId.isValid) { - put(SERVICE_ID, contact.serviceId.toString()) + if (contact.aci.isValid) { + put(ACI_COLUMN, contact.aci.toString()) } if (FeatureFlags.phoneNumberPrivacy()) { @@ -3918,14 +3994,14 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da put(UNREGISTERED_TIMESTAMP, contact.unregisteredTimestamp) if (contact.unregisteredTimestamp > 0L) { put(REGISTERED, RegisteredState.NOT_REGISTERED.id) - } else if (contact.serviceId.isValid) { + } else if (contact.aci.isValid) { put(REGISTERED, RegisteredState.REGISTERED.id) } else { Log.w(TAG, "Contact is marked as registered, but has no serviceId! Can't locally mark registered. (Phone: ${contact.number.orElse("null")}, Username: ${username?.isNotEmpty()})") } if (isInsert) { - put(AVATAR_COLOR, AvatarColorHash.forAddress(contact.serviceId.toString(), contact.number.orNull()).serialize()) + put(AVATAR_COLOR, AvatarColorHash.forAddress(contact.aci.toString(), contact.number.orNull()).serialize()) } } } @@ -4006,7 +4082,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da writableDatabase .update(TABLE_NAME) .values( - SERVICE_ID to null, + ACI_COLUMN to null, PNI_COLUMN to null ) .run { @@ -4081,7 +4157,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da writableDatabase.execSQL( """ UPDATE $TABLE_NAME - SET $SERVICE_ID = $PNI_COLUMN + SET $ACI_COLUMN = $PNI_COLUMN WHERE $ID = ? AND $PNI_COLUMN NOT NULL """, SqlUtil.buildArgs(recipientId) @@ -4156,7 +4232,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da return RecipientRecord( id = recipientId, - serviceId = ServiceId.parseOrNull(cursor.requireString(SERVICE_ID)), + aci = ACI.parseOrNull(cursor.requireString(ACI_COLUMN)), pni = PNI.parseOrNull(cursor.requireString(PNI_COLUMN)), username = cursor.requireString(USERNAME), e164 = cursor.requireString(PHONE), diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedTable.kt index 2fd3c1e266..2fdc940a97 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedTable.kt @@ -116,12 +116,20 @@ class SenderKeySharedTable internal constructor(context: Context?, databaseHelpe fun deleteAllFor(recipientId: RecipientId) { val recipient = Recipient.resolved(recipientId) if (recipient.hasServiceId()) { - writableDatabase - .delete(TABLE_NAME) - .where("$ADDRESS = ?", recipient.requireServiceId().toString()) - .run() + if (recipient.hasAci()) { + writableDatabase + .delete(TABLE_NAME) + .where("$ADDRESS = ?", recipient.requireAci().toString()) + .run() + } + if (recipient.hasPni()) { + writableDatabase + .delete(TABLE_NAME) + .where("$ADDRESS = ?", recipient.requirePni().toString()) + .run() + } } else { - Log.w(TAG, "Recipient doesn't have a UUID! $recipientId") + Log.w(TAG, "Recipient doesn't have a ServiceId! $recipientId") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt index 4068485e5f..98a9136bcc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt @@ -63,7 +63,6 @@ import org.thoughtcrime.securesms.util.JsonUtils.SaneJSONObject import org.thoughtcrime.securesms.util.LRUCache import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.isScheduled -import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.storage.SignalAccountRecord import org.whispersystems.signalservice.api.storage.SignalAccountRecord.PinnedConversation import org.whispersystems.signalservice.api.storage.SignalContactRecord @@ -1700,7 +1699,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa if (threadRecipient.isPushV2Group) { val inviteAddState = record.gv2AddInviteState if (inviteAddState != null) { - val from = RecipientId.from(ServiceId.from(inviteAddState.addedOrInvitedBy)) + val from = RecipientId.from(inviteAddState.addedOrInvitedBy) return if (inviteAddState.isInvited) { Log.i(TAG, "GV2 invite message request from $from") Extra.forGroupV2invite(from, authorId) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index 71b988c2ad..1007d5d261 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -55,6 +55,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V196_BackCallLinksW import org.thoughtcrime.securesms.database.helpers.migration.V197_DropAvatarColorFromCallLinks import org.thoughtcrime.securesms.database.helpers.migration.V198_AddMacDigestColumn import org.thoughtcrime.securesms.database.helpers.migration.V199_AddThreadActiveColumn +import org.thoughtcrime.securesms.database.helpers.migration.V200_ResetPniColumn /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -63,7 +64,7 @@ object SignalDatabaseMigrations { val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass) - const val DATABASE_VERSION = 199 + const val DATABASE_VERSION = 200 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { @@ -270,6 +271,10 @@ object SignalDatabaseMigrations { if (oldVersion < 199) { V199_AddThreadActiveColumn.migrate(context, db, oldVersion, newVersion) } + + if (oldVersion < 200) { + V200_ResetPniColumn.migrate(context, db, oldVersion, newVersion) + } } @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt index 75de5ac4de..d4ef1d7654 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V149_LegacyMigrations.kt @@ -47,8 +47,8 @@ import org.thoughtcrime.securesms.util.FileUtils import org.thoughtcrime.securesms.util.ServiceUtil import org.thoughtcrime.securesms.util.Triple import org.thoughtcrime.securesms.util.Util -import org.whispersystems.signalservice.api.push.ACI import org.whispersystems.signalservice.api.push.DistributionId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.io.File import java.util.LinkedList import java.util.Locale diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsAndEditMessageMigration.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsAndEditMessageMigration.kt index b55bf2b411..7c493a9bbc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsAndEditMessageMigration.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsAndEditMessageMigration.kt @@ -16,7 +16,7 @@ import org.signal.core.util.requireString import org.thoughtcrime.securesms.database.KeyValueDatabase import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.recipients.RecipientId -import org.whispersystems.signalservice.api.push.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI /** * This is a combination of the edit message and message recipient migrations (would have been V185 and v186), but as they diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V188_FixMessageRecipientsAndEditMessageMigration.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V188_FixMessageRecipientsAndEditMessageMigration.kt index ba6f3a101b..ff9bb0d7e3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V188_FixMessageRecipientsAndEditMessageMigration.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V188_FixMessageRecipientsAndEditMessageMigration.kt @@ -16,7 +16,7 @@ import org.signal.core.util.requireString import org.thoughtcrime.securesms.database.KeyValueDatabase import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.recipients.RecipientId -import org.whispersystems.signalservice.api.push.ACI +import org.whispersystems.signalservice.api.push.ServiceId.ACI /** * This is a fix for a bad situation that could happen during [V185_MessageRecipientsAndEditMessageMigration]. diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V200_ResetPniColumn.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V200_ResetPniColumn.kt new file mode 100644 index 0000000000..aa4d5ed736 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V200_ResetPniColumn.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * This updates the PNI column to have the proper serialized format. + */ +@Suppress("ClassName") +object V200_ResetPniColumn : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("UPDATE recipient SET pni = 'PNI:' || pni WHERE pni NOT NULL") + db.execSQL("ALTER TABLE recipient RENAME COLUMN uuid to aci") + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java index 44abf17c84..7be56d8053 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateMessageFactory.java @@ -12,7 +12,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.DateUtils; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.ArrayList; @@ -31,7 +31,7 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.Spannabl private final ACI selfAci; public GroupCallUpdateMessageFactory(@NonNull Context context, - @NonNull List joinedMembers, + @NonNull List joinedMembers, boolean withTime, @NonNull GroupCallUpdateDetails groupCallUpdateDetails) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt index b99a381a50..3113866d89 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupRecord.kt @@ -176,7 +176,7 @@ class GroupRecord( if (isV2Group) { val serviceId = recipient.serviceId if (serviceId.isPresent) { - return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get().uuid()) + return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get().rawUuid) .isPresent } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java index 9ac330c9e8..684d3bb3a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java @@ -33,7 +33,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.ExpirationUtil; import org.thoughtcrime.securesms.util.SpanUtil; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; -import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceIds; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -72,9 +72,9 @@ final class GroupsV2UpdateMessageProducer { * When the revision of the group is 0, the change is very noisy and only the editor is useful. */ UpdateDescription describeNewGroup(@NonNull DecryptedGroup group, @NonNull DecryptedGroupChange decryptedGroupChange) { - Optional selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getAci().uuid()); + Optional selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getAci().getRawUuid()); if (!selfPending.isPresent() && selfIds.getPni() != null) { - selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getPni().uuid()); + selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getPni().getRawUuid()); } if (selfPending.isPresent()) { @@ -90,8 +90,8 @@ final class GroupsV2UpdateMessageProducer { } } - if (DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getAci().uuid()).isPresent() || - (selfIds.getPni() != null && DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getPni().uuid()).isPresent())) + if (DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getAci().getRawUuid()).isPresent() || + (selfIds.getPni() != null && DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getPni().getRawUuid()).isPresent())) { return updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16); } else { @@ -820,11 +820,11 @@ final class GroupsV2UpdateMessageProducer { @NonNull ByteString uuid1Bytes, @DrawableRes int iconResource) { - ServiceId serviceId = ServiceId.fromByteStringOrUnknown(uuid1Bytes); - RecipientId recipientId = RecipientId.from(serviceId); + ACI aci = ACI.parseOrUnknown(uuid1Bytes); + RecipientId recipientId = RecipientId.from(aci); return UpdateDescription.mentioning( - Collections.singletonList(serviceId), + Collections.singletonList(aci), () -> { List recipientIdList = Collections.singletonList(recipientId); String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, null)); @@ -839,14 +839,14 @@ final class GroupsV2UpdateMessageProducer { @NonNull ByteString uuid2Bytes, @DrawableRes int iconResource) { - ServiceId sid1 = ServiceId.fromByteStringOrUnknown(uuid1Bytes); - ServiceId sid2 = ServiceId.fromByteStringOrUnknown(uuid2Bytes); + ACI aci1 = ACI.parseOrUnknown(uuid1Bytes); + ACI aci2 = ACI.parseOrUnknown(uuid2Bytes); - RecipientId recipientId1 = RecipientId.from(sid1); - RecipientId recipientId2 = RecipientId.from(sid2); + RecipientId recipientId1 = RecipientId.from(aci1); + RecipientId recipientId2 = RecipientId.from(aci2); return UpdateDescription.mentioning( - Arrays.asList(sid1, sid2), + Arrays.asList(aci1, aci2), () -> { List recipientIdList = Arrays.asList(recipientId1, recipientId2); String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, null)); @@ -862,11 +862,11 @@ final class GroupsV2UpdateMessageProducer { @NonNull Object formatArg, @DrawableRes int iconResource) { - ServiceId serviceId = ServiceId.fromByteStringOrUnknown(uuid1Bytes); - RecipientId recipientId = RecipientId.from(serviceId); + ACI aci = ACI.parseOrUnknown(uuid1Bytes); + RecipientId recipientId = RecipientId.from(aci); return UpdateDescription.mentioning( - Collections.singletonList(serviceId), + Collections.singletonList(aci), () -> { List recipientIdList = Collections.singletonList(recipientId); String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, Collections.singletonList(formatArg))); @@ -883,11 +883,11 @@ final class GroupsV2UpdateMessageProducer { @NonNull Object formatArg, @DrawableRes int iconResource) { - ServiceId serviceId = ServiceId.fromByteStringOrUnknown(uuid1Bytes); - RecipientId recipientId = RecipientId.from(serviceId); + ACI aci = ACI.parseOrUnknown(uuid1Bytes); + RecipientId recipientId = RecipientId.from(aci); return UpdateDescription.mentioning( - Collections.singletonList(serviceId), + Collections.singletonList(aci), () -> { List recipientIdList = Collections.singletonList(recipientId); String templateString = context.getResources().getQuantityString(stringRes, quantity, makePlaceholders(recipientIdList, Collections.singletonList(formatArg))); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index 635f2f3228..b6d3fa4964 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -64,6 +64,7 @@ import org.thoughtcrime.securesms.util.ExpirationUtil; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -307,7 +308,7 @@ public abstract class MessageRecord extends DisplayRecord { private static boolean selfCreatedGroup(@NonNull DecryptedGroupChange change) { return change.getRevision() == 0 && - change.getEditor().equals(UuidUtil.toByteString(SignalStore.account().requireAci().uuid())); + change.getEditor().equals(UuidUtil.toByteString(SignalStore.account().requireAci().getRawUuid())); } public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull String body, @Nullable Consumer recipientClickHandler) { @@ -345,13 +346,13 @@ public abstract class MessageRecord extends DisplayRecord { } DecryptedGroup groupState = decryptedGroupV2Context.getGroupState(); - boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), SignalStore.account().requireAci().uuid()).isPresent(); + boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), SignalStore.account().requireAci().getRawUuid()).isPresent(); if (decryptedGroupV2Context.hasChange()) { UUID changeEditor = UuidUtil.fromByteStringOrNull(decryptedGroupV2Context.getChange().getEditor()); if (changeEditor != null) { - return new InviteAddState(invited, changeEditor); + return new InviteAddState(invited, ACI.from(changeEditor)); } } @@ -367,7 +368,7 @@ public abstract class MessageRecord extends DisplayRecord { @NonNull Function stringGenerator, @DrawableRes int iconResource) { - return UpdateDescription.mentioning(Collections.singletonList(recipient.getServiceId().orElse(ServiceId.UNKNOWN)), + return UpdateDescription.mentioning(Collections.singletonList(recipient.getAci().orElse(ACI.UNKNOWN)), () -> new SpannableString(stringGenerator.apply(recipient.resolve())), iconResource); } @@ -435,10 +436,10 @@ public abstract class MessageRecord extends DisplayRecord { public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) { GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body); - List joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList()) + List joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList()) .map(UuidUtil::parseOrNull) .withoutNulls() - .map(ServiceId::from) + .map(ACI::from) .toList(); UpdateDescription.SpannableFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails); @@ -467,7 +468,7 @@ public abstract class MessageRecord extends DisplayRecord { return false; } - return isGroupV2JoinRequest(UuidUtil.toByteString(serviceId.uuid())); + return isGroupV2JoinRequest(UuidUtil.toByteString(serviceId.getRawUuid())); } public boolean isGroupV2JoinRequest(@NonNull ByteString uuid) { @@ -489,7 +490,7 @@ public abstract class MessageRecord extends DisplayRecord { DecryptedGroupChange change = decryptedGroupV2Context.getChange(); return change.getNewRequestingMembersCount() > 0 && change.getDeleteRequestingMembersCount() > 0 && - (serviceId == null || change.getEditor().equals(UuidUtil.toByteString(serviceId.uuid()))); + (serviceId == null || change.getEditor().equals(UuidUtil.toByteString(serviceId.getRawUuid()))); } return false; } @@ -748,14 +749,14 @@ public abstract class MessageRecord extends DisplayRecord { public static final class InviteAddState { private final boolean invited; - private final UUID addedOrInvitedBy; + private final ACI addedOrInvitedBy; - public InviteAddState(boolean invited, @NonNull UUID addedOrInvitedBy) { + public InviteAddState(boolean invited, @NonNull ACI addedOrInvitedBy) { this.invited = invited; this.addedOrInvitedBy = addedOrInvitedBy; } - public @NonNull UUID getAddedOrInvitedBy() { + public @NonNull ACI getAddedOrInvitedBy() { return addedOrInvitedBy; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt index 24091260fd..7cafb8cfda 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt @@ -19,8 +19,9 @@ import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId import org.thoughtcrime.securesms.wallpaper.ChatWallpaper -import org.whispersystems.signalservice.api.push.PNI import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import java.util.Optional /** @@ -28,7 +29,7 @@ import java.util.Optional */ data class RecipientRecord( val id: RecipientId, - val serviceId: ServiceId?, + val aci: ACI?, val pni: PNI?, val username: String?, val e164: String?, @@ -89,21 +90,23 @@ data class RecipientRecord( } fun e164Only(): Boolean { - return this.e164 != null && this.serviceId == null + return this.e164 != null && this.aci == null } - fun sidOnly(sid: ServiceId): Boolean { - return this.e164 == null && this.serviceId == sid && (this.pni == null || this.pni == sid) + fun pniOnly(): Boolean { + return this.e164 == null && this.aci == null && this.pni != null } - fun sidIsPni(): Boolean { - return this.serviceId != null && this.pni != null && this.serviceId == this.pni + fun aciOnly(): Boolean { + return this.e164 == null && this.pni == null && this.aci != null } fun pniAndAci(): Boolean { - return this.serviceId != null && this.pni != null && this.serviceId != this.pni + return this.aci != null && this.pni != null } + val serviceId: ServiceId? = this.aci ?: this.pni + /** * A bundle of data that's only necessary when syncing to storage service, not for a * [Recipient]. diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/UpdateDescription.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/UpdateDescription.java index 5f8e11c864..9eaaefb4ee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/UpdateDescription.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/UpdateDescription.java @@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.Collection; @@ -18,6 +19,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /** * Contains a list of people mentioned in an update message and a function to create the update message. @@ -28,14 +30,14 @@ public final class UpdateDescription { Spannable create(); } - private final Collection mentioned; - private final SpannableFactory stringFactory; - private final Spannable staticString; - private final int lightIconResource; - private final int lightTint; - private final int darkTint; + private final Collection mentioned; + private final SpannableFactory stringFactory; + private final Spannable staticString; + private final int lightIconResource; + private final int lightTint; + private final int darkTint; - private UpdateDescription(@NonNull Collection mentioned, + private UpdateDescription(@NonNull Collection mentioned, @Nullable SpannableFactory stringFactory, @Nullable Spannable staticString, @DrawableRes int iconResource, @@ -60,11 +62,11 @@ public final class UpdateDescription { * @param mentioned UUIDs of recipients that are mentioned in the string. * @param stringFactory The background method for generating the string. */ - public static UpdateDescription mentioning(@NonNull Collection mentioned, + public static UpdateDescription mentioning(@NonNull Collection mentioned, @NonNull SpannableFactory stringFactory, @DrawableRes int iconResource) { - return new UpdateDescription(ServiceId.filterKnown(mentioned), + return new UpdateDescription(mentioned.stream().filter(ACI::isValid).collect(Collectors.toList()), stringFactory, null, iconResource, @@ -125,7 +127,7 @@ public final class UpdateDescription { } @AnyThread - public @NonNull Collection getMentioned() { + public @NonNull Collection getMentioned() { return mentioned; } @@ -156,7 +158,7 @@ public final class UpdateDescription { ); } - Set allMentioned = new HashSet<>(); + Set allMentioned = new HashSet<>(); for (UpdateDescription updateDescription : updateDescriptions) { allMentioned.addAll(updateDescription.getMentioned()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index 6a6b908f68..f905e68981 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -85,8 +85,8 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.SignalWebSocket; import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.services.CallLinksService; import org.whispersystems.signalservice.api.services.DonationsService; import org.whispersystems.signalservice.api.services.ProfileService; diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java index 1c8284bb7c..1a80182132 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java @@ -319,13 +319,13 @@ public final class GroupManager { GroupTable.V2GroupProperties groupProperties = SignalDatabase.groups().requireGroup(groupId).requireV2GroupProperties(); Recipient recipient = Recipient.resolved(recipientId); - if (groupProperties.getBannedMembers().contains(recipient.requireServiceId().uuid())) { + if (groupProperties.getBannedMembers().contains(recipient.requireServiceId().getRawUuid())) { Log.i(TAG, "Attempt to ban already banned recipient: " + recipientId); return; } try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) { - editor.ban(recipient.requireServiceId().uuid()); + editor.ban(recipient.requireServiceId().getRawUuid()); } } @@ -336,7 +336,7 @@ public final class GroupManager { throws GroupChangeBusyException, IOException, GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException { try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) { - editor.unban(Collections.singleton(Recipient.resolved(recipientId).requireServiceId().uuid())); + editor.unban(Collections.singleton(Recipient.resolved(recipientId).requireServiceId().getRawUuid())); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java index 5525d3f571..6a113dafcc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java @@ -64,8 +64,8 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException; import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceIds; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; @@ -176,7 +176,7 @@ final class GroupManagerV2 { Map uuidCipherTexts = new HashMap<>(); for (Recipient recipient : recipients) { - uuidCipherTexts.put(recipient.requireServiceId().uuid(), clientZkGroupCipher.encryptUuid(recipient.requireServiceId().uuid())); + uuidCipherTexts.put(recipient.requireServiceId().getRawUuid(), clientZkGroupCipher.encryptUuid(recipient.requireServiceId().getRawUuid())); } return uuidCipherTexts; @@ -231,7 +231,7 @@ final class GroupManagerV2 { return latest; } - Optional selfInFullMemberList = DecryptedGroupUtil.findMemberByUuid(latest.getMembersList(), selfAci.uuid()); + Optional selfInFullMemberList = DecryptedGroupUtil.findMemberByUuid(latest.getMembersList(), selfAci.getRawUuid()); if (!selfInFullMemberList.isPresent()) { return latest; @@ -356,7 +356,7 @@ final class GroupManagerV2 { groupCandidates = GroupCandidate.withoutExpiringProfileKeyCredentials(groupCandidates); } - return commitChangeWithConflictResolution(selfAci, groupOperations.createModifyGroupMembershipChange(groupCandidates, bannedMembers, selfAci.uuid())); + return commitChangeWithConflictResolution(selfAci, groupOperations.createModifyGroupMembershipChange(groupCandidates, bannedMembers, selfAci.getRawUuid())); } @WorkerThread @@ -431,7 +431,7 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException { Set uuids = Stream.of(recipientIds) - .map(r -> Recipient.resolved(r).requireServiceId().uuid()) + .map(r -> Recipient.resolved(r).requireServiceId().getRawUuid()) .collect(Collectors.toSet()); return commitChangeWithConflictResolution(selfAci, groupOperations.createApproveGroupJoinRequest(uuids)); @@ -442,7 +442,7 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException { Set uuids = Stream.of(recipientIds) - .map(r -> Recipient.resolved(r).requireServiceId().uuid()) + .map(r -> Recipient.resolved(r).requireServiceId().getRawUuid()) .collect(Collectors.toSet()); return commitChangeWithConflictResolution(selfAci, groupOperations.createRefuseGroupJoinRequest(uuids, true, v2GroupProperties.getDecryptedGroup().getBannedMembersList())); @@ -454,7 +454,7 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException { Recipient recipient = Recipient.resolved(recipientId); - return commitChangeWithConflictResolution(selfAci, groupOperations.createChangeMemberRole(recipient.requireServiceId().uuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT)); + return commitChangeWithConflictResolution(selfAci, groupOperations.createChangeMemberRole(recipient.requireServiceId().getRawUuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT)); } @WorkerThread @@ -463,9 +463,9 @@ final class GroupManagerV2 { { GroupRecord groupRecord = groupDatabase.requireGroup(groupId); DecryptedGroup decryptedGroup = groupRecord.requireV2GroupProperties().getDecryptedGroup(); - Optional selfMember = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), selfAci.uuid()); - Optional aciPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfAci.uuid()); - Optional pniPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfPni.uuid()); + Optional selfMember = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), selfAci.getRawUuid()); + Optional aciPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfAci.getRawUuid()); + Optional pniPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfPni.getRawUuid()); Optional selfPendingMember = Optional.empty(); ServiceId serviceId = selfAci; @@ -494,7 +494,7 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException { return commitChangeWithConflictResolution(selfAci, - groupOperations.createRemoveMembersChange(Collections.singleton(serviceId.uuid()), + groupOperations.createRemoveMembersChange(Collections.singleton(serviceId.getRawUuid()), ban, ban ? v2GroupProperties.getDecryptedGroup().getBannedMembersList() : Collections.emptyList()), @@ -506,9 +506,9 @@ final class GroupManagerV2 { @NonNull GroupManager.GroupActionResult addMemberAdminsAndLeaveGroup(Collection newAdmins) throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException { - List newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).requireServiceId().uuid()).toList(); + List newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).requireServiceId().getRawUuid()).toList(); - return commitChangeWithConflictResolution(selfAci, groupOperations.createLeaveAndPromoteMembersToAdmin(selfAci.uuid(), + return commitChangeWithConflictResolution(selfAci, groupOperations.createLeaveAndPromoteMembersToAdmin(selfAci.getRawUuid(), newAdminRecipients)); } @@ -518,7 +518,7 @@ final class GroupManagerV2 { { ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey(); DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup(); - Optional selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.uuid()); + Optional selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.getRawUuid()); if (!selfInGroup.isPresent()) { Log.w(TAG, "Self not in group " + groupId); @@ -548,15 +548,15 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException { DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup(); - Optional selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.uuid()); + Optional selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.getRawUuid()); if (selfInGroup.isPresent()) { Log.w(TAG, "Self already in group"); return null; } - Optional aciInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfAci.uuid()); - Optional pniInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfPni.uuid()); + Optional aciInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfAci.getRawUuid()); + Optional pniInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfPni.getRawUuid()); GroupCandidate groupCandidate = groupCandidateHelper.recipientIdToCandidate(Recipient.self().getId()); @@ -650,7 +650,7 @@ final class GroupManagerV2 { throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException { boolean refetchedAddMemberCredentials = false; - change.setSourceUuid(UuidUtil.toByteString(authServiceId.uuid())); + change.setSourceUuid(UuidUtil.toByteString(authServiceId.getRawUuid())); for (int attempt = 0; attempt < 5; attempt++) { try { @@ -704,7 +704,7 @@ final class GroupManagerV2 { GroupChange.Actions changeActions = change.build(); return GroupChangeUtil.resolveConflict(groupUpdateResult.getLatestServer(), - groupOperations.decryptChange(changeActions, authServiceId.uuid()), + groupOperations.decryptChange(changeActions, authServiceId.getRawUuid()), changeActions); } catch (VerificationFailedException | InvalidGroupStateException ex) { throw new GroupChangeFailedException(ex); @@ -1203,7 +1203,7 @@ final class GroupManagerV2 { void cancelJoinRequest() throws GroupChangeFailedException, IOException { - Set uuids = Collections.singleton(selfAci.uuid()); + Set uuids = Collections.singleton(selfAci.getRawUuid()); GroupChange signedGroupChange; try { @@ -1331,8 +1331,9 @@ final class GroupManagerV2 { } private static @NonNull List getPendingMemberRecipientIds(@NonNull List newPendingMembersList) { + // TODO [greyson][ServiceId] Pending members can be ACI's or PNI's return Stream.of(DecryptedGroupUtil.pendingToUuidList(newPendingMembersList)) - .map(uuid -> RecipientId.from(ServiceId.from(uuid))) + .map(uuid -> RecipientId.from(ACI.from(uuid))) .toList(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java index 2a7edab746..7c06d58f3c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java @@ -80,12 +80,12 @@ public final class GroupProtoUtil { @WorkerThread public static Recipient pendingMemberToRecipient(@NonNull Context context, @NonNull DecryptedPendingMember pendingMember) { - return uuidByteStringToRecipient(context, pendingMember.getUuid()); + return pendingMemberServiceIdToRecipient(context, pendingMember.getUuid()); } @WorkerThread - public static Recipient uuidByteStringToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) { - ServiceId serviceId = ServiceId.fromByteString(uuidByteString); + public static Recipient pendingMemberServiceIdToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) { + ServiceId serviceId = ServiceId.parseOrThrow(uuidByteString); if (serviceId.isUnknown()) { return Recipient.UNKNOWN; @@ -96,7 +96,7 @@ public final class GroupProtoUtil { @WorkerThread public static @NonNull RecipientId uuidByteStringToRecipientId(@NonNull ByteString uuidByteString) { - ServiceId serviceId = ServiceId.fromByteString(uuidByteString); + ServiceId serviceId = ServiceId.parseOrThrow(uuidByteString); if (serviceId.isUnknown()) { return RecipientId.UNKNOWN; diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV2Authorization.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV2Authorization.java index 075ded4436..4c4de6a521 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV2Authorization.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV2Authorization.java @@ -4,7 +4,6 @@ import androidx.annotation.NonNull; import org.signal.core.util.logging.Log; import org.signal.libsignal.zkgroup.GenericServerPublicParams; -import org.signal.libsignal.zkgroup.GenericServerSecretParams; import org.signal.libsignal.zkgroup.VerificationFailedException; import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPniResponse; import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredential; @@ -12,9 +11,6 @@ import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredentialPresentation import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredentialResponse; import org.signal.libsignal.zkgroup.calllinks.CallLinkSecretParams; import org.signal.libsignal.zkgroup.groups.GroupSecretParams; -import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.BuildConfig; -import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.recipients.Recipient; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api; import org.whispersystems.signalservice.api.groupsv2.GroupsV2AuthorizationString; @@ -130,13 +126,13 @@ public class GroupsV2Authorization { } CallLinkAuthCredential credential = authCredentialResponse.receive( - Recipient.self().requireServiceId().uuid(), + Recipient.self().requireServiceId().getRawUuid(), Instant.ofEpochSecond(todaySeconds), genericServerPublicParams ); return credential.present( - Recipient.self().requireServiceId().uuid(), + Recipient.self().requireServiceId().getRawUuid(), Instant.ofEpochSecond(todaySeconds), genericServerPublicParams, callLinkSecretParams diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java b/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java index 2e469b2a81..e41287a6f0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/LiveGroup.java @@ -111,7 +111,7 @@ public final class LiveGroup { return Stream.of(requestingMembersList) .map(requestingMember -> { - Recipient recipient = Recipient.externalPush(ServiceId.fromByteString(requestingMember.getUuid())); + Recipient recipient = Recipient.externalPush(ServiceId.parseOrThrow(requestingMember.getUuid())); return new GroupMemberEntry.RequestingMember(recipient, selfAdmin); }) .toList(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java index cf414f5a2c..af63517fdc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/invited/PendingMemberInvitesRepository.java @@ -77,7 +77,7 @@ final class PendingMemberInvitesRepository { } } } else { - Recipient inviter = GroupProtoUtil.uuidByteStringToRecipient(context, inviterUuid); + Recipient inviter = GroupProtoUtil.pendingMemberServiceIdToRecipient(context, inviterUuid); ArrayList uuidCipherTexts = new ArrayList<>(invitedMembers.size()); for (DecryptedPendingMember pendingMember : invitedMembers) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupCandidateHelper.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupCandidateHelper.java index 6f3f807ab7..8344331aa2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupCandidateHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupCandidateHelper.java @@ -51,7 +51,7 @@ public class GroupCandidateHelper { } Optional expiringProfileKeyCredential = Optional.ofNullable(recipient.getExpiringProfileKeyCredential()); - GroupCandidate candidate = new GroupCandidate(serviceId.uuid(), expiringProfileKeyCredential); + GroupCandidate candidate = new GroupCandidate(serviceId.getRawUuid(), expiringProfileKeyCredential); if (!candidate.hasValidProfileKeyCredential()) { recipientTable.clearProfileKeyCredential(recipient.getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java index 35ac4542ca..da586e0cd9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySet.java @@ -12,6 +12,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.protos.groups.local.DecryptedMember; import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -97,11 +98,11 @@ public final class ProfileKeySet { } if (memberUuid.equals(changeSource)) { - authoritativeProfileKeys.put(ServiceId.from(memberUuid), profileKey); - profileKeys.remove(ServiceId.from(memberUuid)); + authoritativeProfileKeys.put(ACI.from(memberUuid), profileKey); + profileKeys.remove(ACI.from(memberUuid)); } else { - if (!authoritativeProfileKeys.containsKey(ServiceId.from(memberUuid))) { - profileKeys.put(ServiceId.from(memberUuid), profileKey); + if (!authoritativeProfileKeys.containsKey(ACI.from(memberUuid))) { + profileKeys.put(ACI.from(memberUuid), profileKey); } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java index f9f3bd4334..aba0807edc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.java @@ -55,7 +55,7 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api; import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException; import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException; import org.whispersystems.signalservice.api.groupsv2.PartialDecryptedGroup; -import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceIds; import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.push.exceptions.GroupNotFoundException; @@ -171,13 +171,13 @@ public class GroupsV2StateProcessor { } private StateProcessorForGroup(@NonNull ServiceIds serviceIds, - @NonNull Context context, - @NonNull GroupTable groupDatabase, - @NonNull GroupsV2Api groupsV2Api, - @NonNull GroupsV2Authorization groupsV2Authorization, - @NonNull GroupMasterKey groupMasterKey, - @NonNull GroupSecretParams groupSecretParams, - @NonNull RecipientTable recipientTable) + @NonNull Context context, + @NonNull GroupTable groupDatabase, + @NonNull GroupsV2Api groupsV2Api, + @NonNull GroupsV2Authorization groupsV2Authorization, + @NonNull GroupMasterKey groupMasterKey, + @NonNull GroupSecretParams groupSecretParams, + @NonNull RecipientTable recipientTable) { this.serviceIds = serviceIds; this.context = context; @@ -425,23 +425,23 @@ public class GroupsV2StateProcessor { throw new IOException(e); } - if (localState != null && localState.getRevision() >= latestServerGroup.getRevision() && GroupProtoUtil.isMember(serviceIds.getAci().uuid(), localState.getMembersList())) { + if (localState != null && localState.getRevision() >= latestServerGroup.getRevision() && GroupProtoUtil.isMember(serviceIds.getAci().getRawUuid(), localState.getMembersList())) { info("Local state is at or later than server"); return new GroupUpdateResult(GroupState.GROUP_CONSISTENT_OR_AHEAD, null); } - if (latestRevisionOnly || !GroupProtoUtil.isMember(serviceIds.getAci().uuid(), latestServerGroup.getMembersList())) { + if (latestRevisionOnly || !GroupProtoUtil.isMember(serviceIds.getAci().getRawUuid(), latestServerGroup.getMembersList())) { info("Latest revision or not a member, use latest only"); inputGroupState = new GlobalGroupState(localState, Collections.singletonList(new ServerGroupLogEntry(latestServerGroup.getFullyDecryptedGroup(), null))); } else { - int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, serviceIds.getAci().uuid()); + int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, serviceIds.getAci().getRawUuid()); int logsNeededFrom = localState != null ? Math.max(localState.getRevision(), revisionWeWereAdded) : revisionWeWereAdded; boolean includeFirstState = forceIncludeFirst || localState == null || localState.getRevision() < 0 || localState.getRevision() == revisionWeWereAdded || - !GroupProtoUtil.isMember(serviceIds.getAci().uuid(), localState.getMembersList()) || + !GroupProtoUtil.isMember(serviceIds.getAci().getRawUuid(), localState.getMembersList()) || (revision == LATEST && localState.getRevision() + 1 < latestServerGroup.getRevision()); info("Requesting from server currentRevision: " + (localState != null ? localState.getRevision() : "null") + @@ -556,7 +556,7 @@ public class GroupsV2StateProcessor { } Recipient groupRecipient = Recipient.externalGroupExact(groupId); - UUID selfUuid = serviceIds.getAci().uuid(); + UUID selfUuid = serviceIds.getAci().getRawUuid(); DecryptedGroup decryptedGroup = groupDatabase.requireGroup(groupId) .requireV2GroupProperties() @@ -668,17 +668,17 @@ public class GroupsV2StateProcessor { @VisibleForTesting static class ProfileAndMessageHelper { - private final Context context; - private final ServiceId serviceId; + private final Context context; + private final ACI aci; private final GroupId.V2 groupId; private final RecipientTable recipientTable; @VisibleForTesting GroupMasterKey masterKey; - ProfileAndMessageHelper(@NonNull Context context, @NonNull ServiceId serviceId, @NonNull GroupMasterKey masterKey, @NonNull GroupId.V2 groupId, @NonNull RecipientTable recipientTable) { + ProfileAndMessageHelper(@NonNull Context context, @NonNull ACI aci, @NonNull GroupMasterKey masterKey, @NonNull GroupId.V2 groupId, @NonNull RecipientTable recipientTable) { this.context = context; - this.serviceId = serviceId; + this.aci = aci; this.masterKey = masterKey; this.groupId = groupId; this.recipientTable = recipientTable; @@ -686,15 +686,15 @@ public class GroupsV2StateProcessor { void determineProfileSharing(@NonNull GlobalGroupState inputGroupState, @NonNull DecryptedGroup newLocalState) { if (inputGroupState.getLocalState() != null) { - boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), serviceId.uuid()).isPresent(); + boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), aci.getRawUuid()).isPresent(); if (wasAMemberAlready) { return; } } - Optional selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), serviceId.uuid()); - Optional selfAsPendingOptional = DecryptedGroupUtil.findPendingByUuid(newLocalState.getPendingMembersList(), serviceId.uuid()); + Optional selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), aci.getRawUuid()); + Optional selfAsPendingOptional = DecryptedGroupUtil.findPendingByUuid(newLocalState.getPendingMembersList(), aci.getRawUuid()); if (selfAsMemberOptional.isPresent()) { DecryptedMember selfAsMember = selfAsMemberOptional.get(); @@ -705,7 +705,7 @@ public class GroupsV2StateProcessor { .filter(c -> c != null && c.getRevision() == revisionJoinedAt) .findFirst() .map(c -> Optional.ofNullable(UuidUtil.fromByteStringOrNull(c.getEditor())) - .map(uuid -> Recipient.externalPush(ServiceId.from(uuid)))) + .map(uuid -> Recipient.externalPush(ACI.from(uuid)))) .orElse(Optional.empty()); if (addedByOptional.isPresent()) { @@ -713,7 +713,7 @@ public class GroupsV2StateProcessor { Log.i(TAG, String.format("Added as a full member of %s by %s", groupId, addedBy.getId())); - if (addedBy.isBlocked() && (inputGroupState.getLocalState() == null || !DecryptedGroupUtil.isRequesting(inputGroupState.getLocalState(), serviceId.uuid()))) { + if (addedBy.isBlocked() && (inputGroupState.getLocalState() == null || !DecryptedGroupUtil.isRequesting(inputGroupState.getLocalState(), aci.getRawUuid()))) { Log.i(TAG, "Added by a blocked user. Leaving group."); ApplicationDependencies.getJobManager().add(new LeaveGroupV2Job(groupId)); //noinspection UnnecessaryReturnStatement @@ -730,7 +730,7 @@ public class GroupsV2StateProcessor { } } else if (selfAsPendingOptional.isPresent()) { Optional addedBy = selfAsPendingOptional.flatMap(adder -> Optional.ofNullable(UuidUtil.fromByteStringOrNull(adder.getAddedByUuid())) - .map(uuid -> Recipient.externalPush(ServiceId.from(uuid)))); + .map(uuid -> Recipient.externalPush(ACI.from(uuid)))); if (addedBy.isPresent() && addedBy.get().isBlocked()) { Log.i(TAG, String.format("Added to group %s by a blocked user %s. Leaving group.", groupId, addedBy.get().getId())); @@ -795,9 +795,9 @@ public class GroupsV2StateProcessor { } void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp) { - Optional editor = getEditor(decryptedGroupV2Context).map(ServiceId::from); + Optional editor = getEditor(decryptedGroupV2Context).map(ACI::from); - boolean outgoing = !editor.isPresent() || serviceId.equals(editor.get()); + boolean outgoing = !editor.isPresent() || aci.equals(editor.get()); if (outgoing) { try { @@ -835,7 +835,7 @@ public class GroupsV2StateProcessor { if (changeEditor.isPresent()) { return changeEditor; } else { - Optional pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), serviceId.uuid()); + Optional pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), aci.getRawUuid()); if (pendingByUuid.isPresent()) { return Optional.ofNullable(UuidUtil.fromByteStringOrNull(pendingByUuid.get().getAddedByUuid())); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java index dcaaed5eb2..84b8ac0721 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AutomaticSessionResetJob.java @@ -85,7 +85,7 @@ public class AutomaticSessionResetJob extends BaseJob { @Override protected void onRun() throws Exception { - ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(recipientId, deviceId); + ApplicationDependencies.getProtocolStore().aci().sessions().archiveSessions(recipientId, deviceId); SignalDatabase.senderKeyShared().deleteAllFor(recipientId); insertLocalMessage(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java index 37eac65d31..04b597db36 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java @@ -119,7 +119,7 @@ public final class GroupV2UpdateSelfProfileKeyJob extends BaseJob { continue; } - ByteString selfUuidBytes = UuidUtil.toByteString(Recipient.self().requireServiceId().uuid()); + ByteString selfUuidBytes = UuidUtil.toByteString(Recipient.self().requireAci().getRawUuid()); DecryptedMember selfMember = group.get().requireV2GroupProperties().getDecryptedGroup().getMembersList() .stream() .filter(m -> m.getUuid().equals(selfUuidBytes)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceStorySendSyncJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceStorySendSyncJob.kt index a456ff9435..f97c9dea16 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceStorySendSyncJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceStorySendSyncJob.kt @@ -74,7 +74,7 @@ class MultiDeviceStorySendSyncJob private constructor(parameters: Parameters, pr private fun buildSentTranscript(recipientsSet: Set): SentTranscriptMessage { return SentTranscriptMessage( - Optional.of(SignalServiceAddress(Recipient.self().requireServiceId())), + Optional.of(SignalServiceAddress(Recipient.self().requireAci())), sentTimestamp, Optional.empty(), 0, diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java index 40e27e06c2..6fe3e6e401 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java @@ -33,7 +33,7 @@ import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.messages.SendMessageResult; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2; -import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.push.SignalServiceProtos; @@ -77,8 +77,8 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { Set recipients = Stream.concat(Stream.of(memberUuids), Stream.of(pendingUuids)) .filter(uuid -> !UuidUtil.UNKNOWN_UUID.equals(uuid)) - .filter(uuid -> !SignalStore.account().requireAci().uuid().equals(uuid)) - .map(uuid -> Recipient.externalPush(ServiceId.from(uuid))) + .filter(uuid -> !SignalStore.account().requireAci().getRawUuid().equals(uuid)) + .map(uuid -> Recipient.externalPush(ACI.from(uuid))) .filter(recipient -> recipient.getRegistered() != RecipientTable.RegisteredState.NOT_REGISTERED) .map(Recipient::getId) .collect(Collectors.toSet()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java index 042abd8a05..b1643eecbd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -67,6 +67,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemo import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServicePreview; import org.whispersystems.signalservice.api.messages.shared.SharedContact; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; @@ -325,7 +326,7 @@ public abstract class PushSendJob extends SendJob { protected Optional getQuoteFor(OutgoingMessage message) throws IOException { if (message.getOutgoingQuote() == null) return Optional.empty(); if (message.isMessageEdit()) { - return Optional.of(new SignalServiceDataMessage.Quote(0, ServiceId.UNKNOWN, "", null, null, SignalServiceDataMessage.Quote.Type.NORMAL, null)); + return Optional.of(new SignalServiceDataMessage.Quote(0, ACI.UNKNOWN, "", null, null, SignalServiceDataMessage.Quote.Type.NORMAL, null)); } long quoteId = message.getOutgoingQuote().getId(); @@ -383,7 +384,7 @@ public abstract class PushSendJob extends SendJob { if (quoteAuthorRecipient.isMaybeRegistered()) { return Optional.of(new SignalServiceDataMessage.Quote(quoteId, RecipientUtil.getOrFetchServiceId(context, quoteAuthorRecipient), quoteBody, quoteAttachments, quoteMentions, quoteType.getDataMessageType(), bodyRanges)); } else if (quoteAuthorRecipient.hasServiceId()) { - return Optional.of(new SignalServiceDataMessage.Quote(quoteId, quoteAuthorRecipient.requireServiceId(), quoteBody, quoteAttachments, quoteMentions, quoteType.getDataMessageType(), bodyRanges)); + return Optional.of(new SignalServiceDataMessage.Quote(quoteId, quoteAuthorRecipient.requireAci(), quoteBody, quoteAttachments, quoteMentions, quoteType.getDataMessageType(), bodyRanges)); } else { return Optional.empty(); } @@ -451,7 +452,7 @@ public abstract class PushSendJob extends SendJob { List getMentionsFor(@NonNull List mentions) { return Stream.of(mentions) - .map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireServiceId(), m.getStart(), m.getLength())) + .map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireAci(), m.getStart(), m.getLength())) .toList(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt index 5b74927b7a..4125a315b4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/AccountValues.kt @@ -22,8 +22,8 @@ import org.thoughtcrime.securesms.service.KeyCachingService import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.push.ServiceIds import org.whispersystems.signalservice.api.push.SignalServiceAddress import java.security.SecureRandom @@ -85,6 +85,12 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal if (!store.containsKey(KEY_ACI_IDENTITY_PUBLIC_KEY)) { migrateFromSharedPrefsV2(ApplicationDependencies.getApplication()) } + + store.getString(KEY_PNI, null)?.let { pni -> + if (!pni.startsWith("PNI:")) { + store.beginWrite().putString(KEY_PNI, "PNI:$pni").commit() + } + } } public override fun onFirstEverAppLaunch() = Unit diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java index 8a2bd37380..ad024c7f45 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java @@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.VersionTracker; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.Arrays; import java.util.LinkedList; diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt index 169c79ab16..b0b16beace 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/CallMessageProcessor.kt @@ -42,7 +42,7 @@ object CallMessageProcessor { handleCallHangupMessage(envelope, metadata, hangup, senderRecipient.id, callMessage.hasLegacyHangup()) } callMessage.hasBusy() -> handleCallBusyMessage(envelope, metadata, callMessage.busy, senderRecipient.id) - callMessage.hasOpaque() -> handleCallOpaqueMessage(envelope, metadata, callMessage.opaque, senderRecipient.requireServiceId(), serverDeliveredTimestamp) + callMessage.hasOpaque() -> handleCallOpaqueMessage(envelope, metadata, callMessage.opaque, senderRecipient.requireAci(), serverDeliveredTimestamp) } } @@ -146,7 +146,7 @@ object CallMessageProcessor { ApplicationDependencies.getSignalCallManager() .receivedOpaqueMessage( OpaqueMessageMetadata( - senderServiceId.uuid(), + senderServiceId.rawUuid, opaque.data.toByteArray(), metadata.sourceDeviceId, messageAgeSeconds diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt index 4ea1030467..53c9bae541 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt @@ -95,6 +95,7 @@ import org.thoughtcrime.securesms.util.isStory import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata import org.whispersystems.signalservice.api.payments.Money import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.util.OptionalUtil.asOptional import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content @@ -992,10 +993,10 @@ object DataMessageProcessor { return mentionBodyRanges .filter { it.hasMentionAci() } .mapNotNull { - val serviceId = ServiceId.parseOrNull(it.mentionAci) + val aci = ACI.parseOrNull(it.mentionAci) - if (serviceId != null && !serviceId.isUnknown) { - val id = Recipient.externalPush(serviceId).id + if (aci != null && !aci.isUnknown) { + val id = Recipient.externalPush(aci).id Mention(id, it.start, it.length) } else { null diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index cba4db49ee..e30e324507 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -537,7 +537,7 @@ public class MessageContentProcessor { Optional groupRecord = groupDatabase.getGroup(groupId); if (groupRecord.isPresent() && !groupRecord.get().getMembers().contains(senderRecipient.getId())) { - log(String.valueOf(content.getTimestamp()), "Ignoring GV2 message from member not in group " + groupId + ". Sender: " + senderRecipient.getId() + " | " + senderRecipient.requireServiceId()); + log(String.valueOf(content.getTimestamp()), "Ignoring GV2 message from member not in group " + groupId + ". Sender: " + senderRecipient.getId() + " | " + senderRecipient.requireAci()); return true; } @@ -739,7 +739,7 @@ public class MessageContentProcessor { } ApplicationDependencies.getSignalCallManager() - .receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireServiceId().uuid(), + .receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireAci().getRawUuid(), message.getOpaque(), content.getSenderDevice(), messageAgeSeconds)); @@ -843,7 +843,7 @@ public class MessageContentProcessor { log(content.getTimestamp(), "Unknown group message."); warn(content.getTimestamp(), "Received a GV2 message for a group we have no knowledge of -- attempting to fix this state."); - ServiceId authServiceId = ServiceId.parseOrNull(content.getDestinationUuid()); + ServiceId authServiceId = ServiceId.parseOrNull(content.getDestinationServiceId()); if (authServiceId == null) { warn(content.getTimestamp(), "Group message missing destination uuid, defaulting to ACI"); authServiceId = SignalStore.account().requireAci(); @@ -1290,7 +1290,7 @@ public class MessageContentProcessor { return; } - ServiceId serviceId = ServiceId.fromByteString(callEvent.getConversationId()); + ServiceId serviceId = ServiceId.parseOrThrow(callEvent.getConversationId()); RecipientId recipientId = RecipientId.from(serviceId); log(envelopeTimestamp, "Synchronize call event call: " + callId); @@ -3061,7 +3061,7 @@ public class MessageContentProcessor { ratchetKeyMatches(requester, content.getSenderDevice(), decryptionErrorMessage.getRatchetKey().get())) { warn(content.getTimestamp(), "[RetryReceipt-I] Ratchet key matches. Archiving the session."); - ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.getId(), content.getSenderDevice()); + ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.requireServiceId(), content.getSenderDevice()); archivedSession = true; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessorV2.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessorV2.kt index 734fe638cf..deadda5677 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessorV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessorV2.kt @@ -569,7 +569,7 @@ open class MessageContentProcessorV2(private val context: Context) { ratchetKeyMatches(requester, metadata.sourceDeviceId, decryptionErrorMessage.ratchetKey.get()) ) { warn(envelope.timestamp, "[RetryReceipt-I] Ratchet key matches. Archiving the session.") - ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.id, metadata.sourceDeviceId) + ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.requireServiceId(), metadata.sourceDeviceId) archivedSession = true } @@ -604,7 +604,7 @@ open class MessageContentProcessorV2(private val context: Context) { } private fun ratchetKeyMatches(recipient: Recipient, deviceId: Int, ratchetKey: ECPublicKey): Boolean { - val address = recipient.resolve().requireServiceId().toProtocolAddress(deviceId) + val address = recipient.resolve().requireAci().toProtocolAddress(deviceId) val session = ApplicationDependencies.getProtocolStore().aci().loadSession(address) return session.currentRatchetKeyMatches(ratchetKey) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt index 05660a2406..f694922f9c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt @@ -55,8 +55,9 @@ import org.whispersystems.signalservice.api.crypto.SignalGroupSessionBuilder import org.whispersystems.signalservice.api.crypto.SignalServiceCipher import org.whispersystems.signalservice.api.crypto.SignalServiceCipherResult import org.whispersystems.signalservice.api.messages.EnvelopeContentValidator -import org.whispersystems.signalservice.api.push.PNI import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope @@ -158,13 +159,17 @@ object MessageDecryptor { } if (FeatureFlags.phoneNumberPrivacy() && cipherResult.content.hasPniSignatureMessage()) { - handlePniSignatureMessage( - envelope, - cipherResult.metadata.sourceServiceId, - cipherResult.metadata.sourceE164, - cipherResult.metadata.sourceDeviceId, - cipherResult.content.pniSignatureMessage - ) + if (cipherResult.metadata.sourceServiceId is ACI) { + handlePniSignatureMessage( + envelope, + cipherResult.metadata.sourceServiceId as ACI, + cipherResult.metadata.sourceE164, + cipherResult.metadata.sourceDeviceId, + cipherResult.content.pniSignatureMessage + ) + } else { + Log.w(TAG, "${logPrefix(envelope)} Ignoring PNI signature because the sourceServiceId isn't an ACI!") + } } else if (cipherResult.content.hasPniSignatureMessage()) { Log.w(TAG, "${logPrefix(envelope)} Ignoring PNI signature because the feature flag is disabled!") } @@ -295,37 +300,37 @@ object MessageDecryptor { SignalGroupSessionBuilder(ReentrantSessionLock.INSTANCE, GroupSessionBuilder(senderKeyStore)).process(sender, message) } - private fun handlePniSignatureMessage(envelope: Envelope, serviceId: ServiceId, e164: String?, deviceId: Int, pniSignatureMessage: PniSignatureMessage) { - Log.i(TAG, "${logPrefix(envelope, serviceId)} Processing PniSignatureMessage") + private fun handlePniSignatureMessage(envelope: Envelope, aci: ACI, e164: String?, deviceId: Int, pniSignatureMessage: PniSignatureMessage) { + Log.i(TAG, "${logPrefix(envelope, aci)} Processing PniSignatureMessage") val pni: PNI = PNI.parseOrThrow(pniSignatureMessage.pni.toByteArray()) - if (SignalDatabase.recipients.isAssociated(serviceId, pni)) { - Log.i(TAG, "${logPrefix(envelope, serviceId)}[handlePniSignatureMessage] ACI ($serviceId) and PNI ($pni) are already associated.") + if (SignalDatabase.recipients.isAssociated(aci, pni)) { + Log.i(TAG, "${logPrefix(envelope, aci)}[handlePniSignatureMessage] ACI ($aci) and PNI ($pni) are already associated.") return } val identityStore = ApplicationDependencies.getProtocolStore().aci().identities() - val aciAddress = SignalProtocolAddress(serviceId.toString(), deviceId) + val aciAddress = SignalProtocolAddress(aci.toString(), deviceId) val pniAddress = SignalProtocolAddress(pni.toString(), deviceId) val aciIdentity = identityStore.getIdentity(aciAddress) val pniIdentity = identityStore.getIdentity(pniAddress) if (aciIdentity == null) { - Log.w(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] No identity found for ACI address $aciAddress") + Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for ACI address $aciAddress") return } if (pniIdentity == null) { - Log.w(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] No identity found for PNI address $pniAddress") + Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for PNI address $pniAddress") return } if (pniIdentity.verifyAlternateIdentity(aciIdentity, pniSignatureMessage.signature.toByteArray())) { - Log.i(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] PNI signature is valid. Associating ACI ($serviceId) with PNI ($pni)") - SignalDatabase.recipients.getAndPossiblyMergePnpVerified(serviceId, pni, e164) + Log.i(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] PNI signature is valid. Associating ACI ($aci) with PNI ($pni)") + SignalDatabase.recipients.getAndPossiblyMergePnpVerified(aci, pni, e164) } else { - Log.w(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] Invalid PNI signature! Cannot associate ACI ($serviceId) with PNI ($pni)") + Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] Invalid PNI signature! Cannot associate ACI ($aci) with PNI ($pni)") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt index 631a10da79..8ae07c9458 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt @@ -98,6 +98,7 @@ import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.storage.StorageKey import org.whispersystems.signalservice.internal.push.SignalServiceProtos @@ -1227,8 +1228,8 @@ object SyncMessageProcessor { return } - val serviceId = ServiceId.fromByteString(callEvent.conversationId) - val recipientId = RecipientId.from(serviceId) + val aci = ACI.parseOrThrow(callEvent.conversationId) + val recipientId = RecipientId.from(aci) log(envelopeTimestamp, "Synchronize call event call: $callId") diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/PniAccountInitializationMigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/PniAccountInitializationMigrationJob.java index c0840b86a0..2b790eca84 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/PniAccountInitializationMigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/PniAccountInitializationMigrationJob.java @@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.account.PreKeyUpload; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceIdType; import java.io.IOException; diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/PniMigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/PniMigrationJob.java index aa9a6f9a24..6035f6cdc8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/PniMigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/PniMigrationJob.java @@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.keyvalue.SignalStore; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import java.io.IOException; diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/UuidMigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/UuidMigrationJob.java index acf49234d9..81368b2cc7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/UuidMigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/UuidMigrationJob.java @@ -14,7 +14,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.io.IOException; import java.util.Objects; diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java b/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java index 2a7a675b3b..851d716439 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java @@ -191,7 +191,7 @@ public final class MessageGroupContext { List members = new ArrayList<>(decryptedGroupV2Context.getGroupState().getMembersCount()); for (DecryptedMember member : decryptedGroupV2Context.getGroupState().getMembersList()) { - RecipientId recipient = RecipientId.from(ServiceId.fromByteString(member.getUuid())); + RecipientId recipient = RecipientId.from(ServiceId.parseOrThrow(member.getUuid())); if (!Recipient.self().getId().equals(recipient)) { members.add(recipient); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/push/AccountManagerFactory.java b/app/src/main/java/org/thoughtcrime/securesms/push/AccountManagerFactory.java index 89e90cf491..1ba47d6223 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/push/AccountManagerFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/push/AccountManagerFactory.java @@ -13,8 +13,8 @@ import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.util.FeatureFlags; import org.whispersystems.signalservice.api.SignalServiceAccountManager; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; public class AccountManagerFactory { diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipientCache.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipientCache.java index 0b7bd86316..59fe72a5cc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipientCache.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/LiveRecipientCache.java @@ -21,7 +21,7 @@ import org.signal.core.util.CursorUtil; import org.thoughtcrime.securesms.util.LRUCache; import org.signal.core.util.Stopwatch; import org.thoughtcrime.securesms.util.concurrent.FilteredExecutor; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.ArrayList; import java.util.Collection; @@ -160,7 +160,7 @@ public final class LiveRecipientCache { } if (localAci != null) { - selfId = recipientTable.getByServiceId(localAci).orElse(null); + selfId = recipientTable.getByAci(localAci).orElse(null); } if (selfId == null && localE164 != null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java index 3a96dce69e..f35bf4cb23 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -49,7 +49,8 @@ import org.thoughtcrime.securesms.util.AvatarUtil; import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.wallpaper.ChatWallpaper; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.OptionalUtil; @@ -86,7 +87,7 @@ public class Recipient { private final RecipientId id; private final boolean resolving; - private final ServiceId serviceId; + private final ACI aci; private final PNI pni; private final String username; private final String e164; @@ -219,8 +220,8 @@ public class Recipient { * Create a recipient with a full (ACI, PNI, E164) tuple. It is assumed that the association between the PNI and serviceId is trusted. * That means it must be from either storage service or a PNI verification message. */ - public static @NonNull Recipient trustedPush(@NonNull ServiceId serviceId, @Nullable PNI pni, @Nullable String e164) { - if (ServiceId.UNKNOWN.equals(serviceId)) { + public static @NonNull Recipient trustedPush(@NonNull ACI aci, @Nullable PNI pni, @Nullable String e164) { + if (ACI.UNKNOWN.equals(aci) || PNI.UNKNOWN.equals(pni)) { throw new AssertionError("Unknown serviceId!"); } @@ -229,9 +230,9 @@ public class Recipient { RecipientId recipientId; if (FeatureFlags.phoneNumberPrivacy()) { - recipientId = db.getAndPossiblyMergePnpVerified(serviceId, pni, e164); + recipientId = db.getAndPossiblyMergePnpVerified(aci, pni, e164); } else { - recipientId = db.getAndPossiblyMerge(serviceId, e164); + recipientId = db.getAndPossiblyMerge(aci, e164); } Recipient resolved = resolved(recipientId); @@ -242,7 +243,7 @@ public class Recipient { if (!resolved.isRegistered()) { Log.w(TAG, "External push was locally marked unregistered. Marking as registered."); - db.markRegistered(recipientId, serviceId); + db.markRegistered(recipientId, aci); } return resolved; @@ -259,7 +260,7 @@ public class Recipient { */ @WorkerThread static @NonNull Recipient externalPush(@Nullable ServiceId serviceId, @Nullable String e164) { - if (ServiceId.UNKNOWN.equals(serviceId)) { + if (ACI.UNKNOWN.equals(serviceId) || PNI.UNKNOWN.equals(serviceId)) { throw new AssertionError(); } @@ -375,7 +376,7 @@ public class Recipient { Recipient(@NonNull RecipientId id) { this.id = id; this.resolving = true; - this.serviceId = null; + this.aci = null; this.pni = null; this.username = null; this.e164 = null; @@ -433,7 +434,7 @@ public class Recipient { public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) { this.id = id; this.resolving = !resolved; - this.serviceId = details.serviceId; + this.aci = details.aci; this.pni = details.pni; this.username = details.username; this.e164 = details.e164; @@ -661,7 +662,11 @@ public class Recipient { } public @NonNull Optional getServiceId() { - return Optional.ofNullable(serviceId); + return OptionalUtil.or(Optional.ofNullable(aci), Optional.ofNullable(pni)); + } + + public @NonNull Optional getAci() { + return Optional.ofNullable(aci); } public @NonNull Optional getPni() { @@ -750,6 +755,14 @@ public class Recipient { return getServiceId().isPresent(); } + public boolean hasAci() { + return getAci().isPresent(); + } + + public boolean hasPni() { + return getPni().isPresent(); + } + public boolean isServiceIdOnly() { return hasServiceId() && !hasSmsAddress(); } @@ -786,7 +799,22 @@ public class Recipient { * The {@link ServiceId} of the user if available, otherwise throw. */ public @NonNull ServiceId requireServiceId() { - ServiceId resolved = resolving ? resolve().serviceId : serviceId; + Recipient resolved = resolving ? resolve() : this; + + if (resolved.aci != null) { + return resolved.aci; + } else if (resolved.pni != null) { + return resolved.pni; + } else { + throw new MissingAddressError(id); + } + } + + /** + * The {@link ACI} of the user if available, otherwise throw. + */ + public @NonNull ACI requireAci() { + ACI resolved = resolving ? resolve().aci : aci; if (resolved == null) { throw new MissingAddressError(id); @@ -1326,7 +1354,7 @@ public class Recipient { profileSharing == other.profileSharing && isHidden == other.isHidden && forceSmsSelection == other.forceSmsSelection && - Objects.equals(serviceId, other.serviceId) && + Objects.equals(aci, other.aci) && Objects.equals(username, other.username) && Objects.equals(e164, other.e164) && Objects.equals(email, other.email) && diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java index 76b3c3860d..26b60b426c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java @@ -26,8 +26,8 @@ import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.wallpaper.ChatWallpaper; -import org.whispersystems.signalservice.api.push.PNI; -import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import java.util.Collections; import java.util.LinkedList; @@ -36,7 +36,7 @@ import java.util.Optional; public class RecipientDetails { - final ServiceId serviceId; + final ACI aci; final PNI pni; final String username; final String e164; @@ -108,7 +108,7 @@ public class RecipientDetails { this.systemContactPhoto = Util.uri(record.getSystemContactPhotoUri()); this.customLabel = record.getSystemPhoneLabel(); this.contactUri = Util.uri(record.getSystemContactUri()); - this.serviceId = record.getServiceId(); + this.aci = record.getAci(); this.pni = record.getPni(); this.username = record.getUsername(); this.e164 = record.getE164(); @@ -165,7 +165,7 @@ public class RecipientDetails { this.systemContactPhoto = null; this.customLabel = null; this.contactUri = null; - this.serviceId = null; + this.aci = null; this.pni = null; this.username = null; this.e164 = null; @@ -220,7 +220,7 @@ public class RecipientDetails { public static @NonNull RecipientDetails forIndividual(@NonNull Context context, @NonNull RecipientRecord settings) { boolean systemContact = !settings.getSystemProfileName().isEmpty(); boolean isSelf = (settings.getE164() != null && settings.getE164().equals(SignalStore.account().getE164())) || - (settings.getServiceId() != null && settings.getServiceId().equals(SignalStore.account().getAci())); + (settings.getAci() != null && settings.getAci().equals(SignalStore.account().getAci())); boolean isReleaseChannel = settings.getId().equals(SignalStore.releaseChannelValues().getReleaseChannelRecipientId()); RegisteredState registeredState = settings.getRegistered(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java b/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java index 024c090672..218242cf70 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java @@ -38,8 +38,8 @@ import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.account.PreKeyCollection; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.Preconditions; @@ -129,7 +129,7 @@ public final class RegistrationRepository { Preconditions.checkNotNull(response.getPniPreKeyCollection(), "Missing PNI prekey collection!"); ACI aci = ACI.parseOrThrow(response.getVerifyAccountResponse().getUuid()); - PNI pni = PNI.parseOrThrow(response.getVerifyAccountResponse().getPni()); + PNI pni = PNI.parseUnPrefixedOrThrow(response.getVerifyAccountResponse().getPni()); boolean hasPin = response.getVerifyAccountResponse().isStorageCapable(); SignalStore.account().setAci(aci); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java index 6656975fef..f8a2732a55 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java @@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder import org.webrtc.PeerConnection; import org.webrtc.VideoTrack; import org.whispersystems.signalservice.api.messages.calls.OfferMessage; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.ArrayList; @@ -91,7 +92,7 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { seen.add(Recipient.self()); for (GroupCall.RemoteDeviceState device : remoteDeviceStates) { - Recipient recipient = Recipient.externalPush(ServiceId.from(device.getUserId())); + Recipient recipient = Recipient.externalPush(ACI.from(device.getUserId())); CallParticipantId callParticipantId = new CallParticipantId(device.getDemuxId(), recipient.getId()); CallParticipant callParticipant = participants.get(callParticipantId); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupCallRingCheckInfo.kt b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupCallRingCheckInfo.kt index 406e241b55..4be4d74c4a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupCallRingCheckInfo.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupCallRingCheckInfo.kt @@ -3,12 +3,12 @@ package org.thoughtcrime.securesms.service.webrtc import org.signal.ringrtc.CallManager import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.recipients.RecipientId -import java.util.UUID +import org.whispersystems.signalservice.api.push.ServiceId.ACI data class GroupCallRingCheckInfo( val recipientId: RecipientId, val groupId: GroupId.V2, val ringId: Long, - val ringerUuid: UUID, + val ringerAci: ACI, val ringUpdate: CallManager.RingUpdate ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java index 96820a6a18..70ff27af89 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java @@ -158,8 +158,8 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor { webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, remoteUserRangTheCall, true); List members = new ArrayList<>(peekInfo.getJoinedMembers()); - if (!members.contains(SignalStore.account().requireAci().uuid())) { - members.add(SignalStore.account().requireAci().uuid()); + if (!members.contains(SignalStore.account().requireAci().getRawUuid())) { + members.add(SignalStore.account().requireAci().getRawUuid()); } webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, WebRtcUtil.isCallFull(peekInfo)); @@ -184,7 +184,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor { String eraId = WebRtcUtil.getGroupCallEraId(groupCall); webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId, false, false); - List members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireServiceId().uuid()).toList(); + List members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireServiceId().getRawUuid()).toList(); webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, false); currentState = currentState.builder() diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java index 167cf73b90..d68cc77ed2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java @@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder; import org.thoughtcrime.securesms.util.NetworkUtil; import org.whispersystems.signalservice.api.messages.calls.OfferMessage; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.List; @@ -120,7 +121,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor { } List callParticipants = Stream.of(peekInfo.getJoinedMembers()) - .map(uuid -> Recipient.externalPush(ServiceId.from(uuid))) + .map(uuid -> Recipient.externalPush(ACI.from(uuid))) .toList(); WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder() diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IdleActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IdleActionProcessor.java index 80e872c1da..a46d3da071 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IdleActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IdleActionProcessor.java @@ -17,8 +17,7 @@ import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.util.FeatureFlags; import org.whispersystems.signalservice.api.messages.calls.OfferMessage; - -import java.util.UUID; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; /** * Action handler for when the system is at rest. Mainly responsible @@ -97,7 +96,7 @@ public class IdleActionProcessor extends WebRtcActionProcessor { @NonNull RemotePeer remotePeerGroup, @NonNull GroupId.V2 groupId, long ringId, - @NonNull UUID sender, + @NonNull ACI sender, @NonNull CallManager.RingUpdate ringUpdate) { Log.i(TAG, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + ringId + " update: " + ringUpdate); @@ -154,11 +153,11 @@ public class IdleActionProcessor extends WebRtcActionProcessor { if (peekInfo.getDeviceCount() == 0) { Log.i(TAG, "No one in the group call, mark as expired and do not ring"); - SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerUuid(), System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST); + SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerAci(), System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST); return currentState; - } else if (peekInfo.getJoinedMembers().contains(Recipient.self().requireServiceId().uuid())) { + } else if (peekInfo.getJoinedMembers().contains(Recipient.self().requireServiceId().getRawUuid())) { Log.i(TAG, "We are already in the call, mark accepted on another device and do not ring"); - SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerUuid(), System.currentTimeMillis(), CallManager.RingUpdate.ACCEPTED_ON_ANOTHER_DEVICE); + SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerAci(), System.currentTimeMillis(), CallManager.RingUpdate.ACCEPTED_ON_ANOTHER_DEVICE); return currentState; } @@ -166,6 +165,6 @@ public class IdleActionProcessor extends WebRtcActionProcessor { .actionProcessor(new IncomingGroupCallActionProcessor(webRtcInteractor)) .build(); - return currentState.getActionProcessor().handleGroupCallRingUpdate(currentState, new RemotePeer(info.getRecipientId()), info.getGroupId(), info.getRingId(), info.getRingerUuid(), info.getRingUpdate()); + return currentState.getActionProcessor().handleGroupCallRingUpdate(currentState, new RemotePeer(info.getRecipientId()), info.getGroupId(), info.getRingId(), info.getRingerAci(), info.getRingUpdate()); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java index 3f49eb32e2..46eced2865 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java @@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.util.NetworkUtil; import org.thoughtcrime.securesms.webrtc.locks.LockManager; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.Optional; @@ -49,7 +50,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro @NonNull RemotePeer remotePeerGroup, @NonNull GroupId.V2 groupId, long ringId, - @NonNull UUID sender, + @NonNull ACI sender, @NonNull CallManager.RingUpdate ringUpdate) { Log.i(TAG, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + Long.toHexString(ringId) + " update: " + ringUpdate); @@ -108,7 +109,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro Log.i(TAG, "Requesting new ring: " + Long.toHexString(ringId)); - Recipient ringerRecipient = Recipient.externalPush(ServiceId.from(sender)); + Recipient ringerRecipient = Recipient.externalPush(sender); SignalDatabase.calls().insertOrUpdateGroupCallFromRingState( ringId, remotePeerGroup.getId(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index 54ca921f8d..c48ebfb3ba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -80,7 +80,7 @@ import org.whispersystems.signalservice.api.messages.calls.OpaqueMessage; import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage; import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo; import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; -import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage; @@ -191,7 +191,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. serviceExecutor.execute(() -> { if (needsToSetSelfUuid) { try { - callManager.setSelfUuid(SignalStore.account().requireAci().uuid()); + callManager.setSelfUuid(SignalStore.account().requireAci().getRawUuid()); needsToSetSelfUuid = false; } catch (CallException e) { Log.w(TAG, "Unable to set self UUID on CallManager", e); @@ -724,14 +724,14 @@ private void processStateless(@NonNull Function1 { - Recipient recipient = Recipient.resolved(RecipientId.from(ServiceId.from(uuid))); + Recipient recipient = Recipient.resolved(RecipientId.from(ACI.from(aciUuid))); if (recipient.isBlocked()) { return; } @@ -826,16 +826,17 @@ private void processStateless(@NonNull Function1 p.handleGroupCallRingUpdate(s, new RemotePeer(group.getRecipientId()), groupId, ringId, sender, ringUpdate)); + process((s, p) -> p.handleGroupCallRingUpdate(s, new RemotePeer(group.getRecipientId()), groupId, ringId, senderAci, ringUpdate)); } else { Log.w(TAG, "Unable to ring unknown/inactive/blocked group."); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java index da6f55c419..6ab8e96646 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java @@ -54,6 +54,7 @@ import org.whispersystems.signalservice.api.messages.calls.HangupMessage; import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage; import org.whispersystems.signalservice.api.messages.calls.OfferMessage; import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.Collection; import java.util.List; @@ -789,7 +790,7 @@ public abstract class WebRtcActionProcessor { @NonNull RemotePeer remotePeerGroup, @NonNull GroupId.V2 groupId, long ringId, - @NonNull UUID sender, + @NonNull ACI sender, @NonNull RingUpdate ringUpdate) { Log.i(tag, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + ringId + " update: " + ringUpdate); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt index 1b4869a6e5..d1fc094b44 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt @@ -45,7 +45,7 @@ class SignalCallLinkManager( linkRootKey: ByteArray, roomId: ByteArray ): CreateCallLinkCredentialPresentation { - val userUuid = Recipient.self().requireServiceId().uuid() + val userUuid = Recipient.self().requireAci().rawUuid val requestContext = CreateCallLinkCredentialRequestContext.forRoom(roomId) val request = requestContext.request diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java index 18a37b3f1b..b1063ae4cc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/storage/ContactRecordProcessor.java @@ -12,8 +12,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.FeatureFlags; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +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.storage.SignalContactRecord; import org.whispersystems.signalservice.api.util.OptionalUtil; @@ -26,7 +26,6 @@ import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Pattern; @@ -81,9 +80,9 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor 0 && remoteRecord.getServiceId() != null && !remoteRecord.getPni().isPresent() && !remoteRecord.getNumber().isPresent()) { + if (remoteRecord.getUnregisteredTimestamp() > 0 && remoteRecord.getAci() != null && !remoteRecord.getPni().isPresent() && !remoteRecord.getNumber().isPresent()) { unregisteredAciOnly.add(remoteRecord); - } else if (remoteRecord.getServiceId() != null && remoteRecord.getServiceId().equals(remoteRecord.getPni().orElse(null))) { + } else if (remoteRecord.getAci() != null && remoteRecord.getAci().equals(remoteRecord.getPni().orElse(null))) { pniE164Only.add(remoteRecord); } } @@ -128,22 +127,19 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor found = recipientTable.getByServiceId(remote.getServiceId()); + Optional found = recipientTable.getByAci(remote.getAci()); - if (!found.isPresent() && remote.getNumber().isPresent()) { + if (found.isEmpty() && remote.getNumber().isPresent()) { found = recipientTable.getByE164(remote.getNumber().get()); } - if (!found.isPresent() && remote.getPni().isPresent()) { - found = recipientTable.getByServiceId(remote.getPni().get()); - } - - if (!found.isPresent() && remote.getPni().isPresent()) { + if (found.isEmpty() && remote.getPni().isPresent()) { found = recipientTable.getByPni(remote.getPni().get()); } @@ -219,8 +211,8 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor currentUserBucket; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/UsernameUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/UsernameUtil.java index 851f0f343b..5ee2ae2d98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/UsernameUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/UsernameUtil.java @@ -13,7 +13,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.util.Base64UrlSafe; diff --git a/app/src/main/java/org/thoughtcrime/securesms/verify/VerifySafetyNumberViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/verify/VerifySafetyNumberViewModel.kt index 17011eb96c..21787cb9c1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/verify/VerifySafetyNumberViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/verify/VerifySafetyNumberViewModel.kt @@ -63,9 +63,9 @@ class VerifySafetyNumberViewModel( e164Fingerprint = SafetyNumberFingerprint(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity, generator.createFor(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity)) } - if (resolved.serviceId.isPresent) { + if (resolved.aci.isPresent) { val localIdentifier = SignalStore.account().requireAci().toByteArray() - val remoteIdentifier = resolved.requireServiceId().toByteArray() + val remoteIdentifier = resolved.requireAci().toByteArray() val version = 2 aciFingerprint = SafetyNumberFingerprint(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity, generator.createFor(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity)) } @@ -97,13 +97,13 @@ class VerifySafetyNumberViewModel( val context: Context = ApplicationDependencies.getApplication() SignalExecutors.BOUNDED.execute { - ReentrantSessionLock.INSTANCE.acquire().use { unused -> + ReentrantSessionLock.INSTANCE.acquire().use { _ -> if (verified) { Log.i(TAG, "Saving identity: $recipientId") ApplicationDependencies.getProtocolStore().aci().identities() .saveIdentityWithoutSideEffects( recipientId, - recipient.resolve().requireServiceId(), + recipient.resolve().requireAci(), remoteIdentity, IdentityTable.VerifiedStatus.VERIFIED, false, diff --git a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt index b4d6b84048..bf03432844 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt @@ -30,7 +30,6 @@ import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.testutil.SystemOutLogger import org.thoughtcrime.securesms.util.IdentityUtil -import org.whispersystems.signalservice.api.push.ACI import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException import org.whispersystems.signalservice.api.services.ProfileService import org.whispersystems.signalservice.internal.ServiceResponse @@ -125,7 +124,7 @@ class SafetyNumberRepositoryTest { @Test fun batchSafetyNumberCheckSync_batchOf1_oneChange() { val other = recipientPool[1] - val otherAci = ACI.from(other.requireServiceId()) + val otherAci = other.requireAci() val otherNewIdentityKey = IdentityKeyUtil.generateIdentityKeyPair().publicKey val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) @@ -146,7 +145,7 @@ class SafetyNumberRepositoryTest { fun batchSafetyNumberCheckSync_batchOf2_oneChange() { val other = recipientPool[1] val secondOther = recipientPool[2] - val otherAci = ACI.from(other.requireServiceId()) + val otherAci = other.requireAci() val otherNewIdentityKey = IdentityKeyUtil.generateIdentityKeyPair().publicKey val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false), ContactSearchKey.RecipientSearchKey(secondOther.id, false)) diff --git a/app/src/test/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelperTest.java b/app/src/test/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelperTest.java index 11bedc77eb..239b50b8bf 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelperTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/contacts/sync/FuzzyPhoneNumberHelperTest.java @@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.contacts.sync; import org.junit.Test; import org.thoughtcrime.securesms.contacts.sync.FuzzyPhoneNumberHelper.InputResult; import org.thoughtcrime.securesms.contacts.sync.FuzzyPhoneNumberHelper.OutputResult; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import java.util.Arrays; import java.util.Collections; diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt b/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt index 52317406ae..d82bf1c830 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/GroupTestUtil.kt @@ -85,15 +85,15 @@ class GroupChangeData(private val revision: Int, private val groupOperations: Gr } fun source(serviceId: ServiceId) { - actionsBuilder.sourceUuid = groupOperations.encryptUuid(serviceId.uuid()) + actionsBuilder.sourceUuid = groupOperations.encryptUuid(serviceId.rawUuid) } fun deleteMember(serviceId: ServiceId) { - actionsBuilder.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(groupOperations.encryptUuid(serviceId.uuid()))) + actionsBuilder.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(groupOperations.encryptUuid(serviceId.rawUuid))) } fun modifyRole(serviceId: ServiceId, role: Member.Role) { - actionsBuilder.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(groupOperations.encryptUuid(serviceId.uuid())).setRole(role)) + actionsBuilder.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(groupOperations.encryptUuid(serviceId.rawUuid)).setRole(role)) } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt b/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt index 4da48710d2..428576af70 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt @@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientDetails import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.wallpaper.ChatWallpaper -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import java.util.Optional import java.util.UUID import kotlin.random.Random @@ -34,7 +34,7 @@ object RecipientDatabaseTestUtils { isSelf: Boolean = false, participants: List = listOf(), recipientId: RecipientId = RecipientId.from(Random.nextLong()), - serviceId: ServiceId? = ServiceId.from(UUID.randomUUID()), + serviceId: ACI? = ACI.from(UUID.randomUUID()), username: String? = null, e164: String? = null, email: String? = null, diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java b/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java index 68b6ac0a76..c0c7cba479 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducerTest.java @@ -26,8 +26,8 @@ import org.signal.storageservice.protos.groups.local.DecryptedMember; import org.signal.storageservice.protos.groups.local.DecryptedPendingMember; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceIds; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -88,8 +88,8 @@ public final class GroupsV2UpdateMessageProducerTest { producer = new GroupsV2UpdateMessageProducer(ApplicationProvider.getApplicationContext(), new ServiceIds(ACI.from(you), PNI.from(UUID.randomUUID())), null); - recipientIdMockedStatic.when(() -> RecipientId.from(ServiceId.from(alice))).thenReturn(aliceId); - recipientIdMockedStatic.when(() -> RecipientId.from(ServiceId.from(bob))).thenReturn(bobId); + recipientIdMockedStatic.when(() -> RecipientId.from(ACI.from(alice))).thenReturn(aliceId); + recipientIdMockedStatic.when(() -> RecipientId.from(ACI.from(bob))).thenReturn(bobId); recipientMockedStatic.when(() -> Recipient.resolved(aliceId)).thenReturn(aliceRecipient); recipientMockedStatic.when(() -> Recipient.resolved(bobId)).thenReturn(bobRecipient); } @@ -1446,7 +1446,7 @@ public final class GroupsV2UpdateMessageProducerTest { } private void assertSingleChangeMentioning(DecryptedGroupChange change, List expectedMentions) { - List expectedMentionSids = expectedMentions.stream().map(ServiceId::from).collect(Collectors.toList()); + List expectedMentionSids = expectedMentions.stream().map(ACI::from).collect(Collectors.toList()); List changes = producer.describeChanges(null, change); diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/model/UpdateDescriptionTest.java b/app/src/test/java/org/thoughtcrime/securesms/database/model/UpdateDescriptionTest.java index c3949c8eb0..9308ee02b6 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/model/UpdateDescriptionTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/database/model/UpdateDescriptionTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.Arrays; @@ -46,7 +47,7 @@ public final class UpdateDescriptionTest { @Test(expected = UnsupportedOperationException.class) public void stringFactory_cannot_call_static_string() { - UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ServiceId.from(UUID.randomUUID())), () -> new SpannableString("update"), 0); + UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), () -> new SpannableString("update"), 0); description.getStaticSpannable(); } @@ -60,7 +61,7 @@ public final class UpdateDescriptionTest { return new SpannableString("update"); }; - UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ServiceId.from(UUID.randomUUID())), stringFactory, 0); + UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory, 0); assertEquals(0, factoryCalls.get()); @@ -74,7 +75,7 @@ public final class UpdateDescriptionTest { public void stringFactory_reevaluated_on_every_call() { AtomicInteger factoryCalls = new AtomicInteger(); UpdateDescription.SpannableFactory stringFactory = () -> new SpannableString( "call" + factoryCalls.incrementAndGet()); - UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ServiceId.from(UUID.randomUUID())), stringFactory, 0); + UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory, 0); assertEquals("call1", description.getSpannable().toString()); assertEquals("call2", description.getSpannable().toString()); @@ -108,8 +109,8 @@ public final class UpdateDescriptionTest { AtomicInteger factoryCalls2 = new AtomicInteger(); UpdateDescription.SpannableFactory stringFactory1 = () -> new SpannableString("update." + factoryCalls1.incrementAndGet()); UpdateDescription.SpannableFactory stringFactory2 = () -> new SpannableString("update." + factoryCalls2.incrementAndGet()); - UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ServiceId.from(UUID.randomUUID())), stringFactory1, 0); - UpdateDescription description2 = UpdateDescription.mentioning(Collections.singletonList(ServiceId.from(UUID.randomUUID())), stringFactory2, 0); + UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory1, 0); + UpdateDescription description2 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory2, 0); factoryCalls1.set(10); factoryCalls2.set(20); @@ -129,9 +130,9 @@ public final class UpdateDescriptionTest { AtomicInteger factoryCalls2 = new AtomicInteger(); UpdateDescription.SpannableFactory stringFactory1 = () -> new SpannableString("update." + factoryCalls1.incrementAndGet()); UpdateDescription.SpannableFactory stringFactory2 = () -> new SpannableString("update." + factoryCalls2.incrementAndGet()); - UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ServiceId.from(UUID.randomUUID())), stringFactory1, 0); + UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory1, 0); UpdateDescription description2 = UpdateDescription.staticDescription("static", 0); - UpdateDescription description3 = UpdateDescription.mentioning(Collections.singletonList(ServiceId.from(UUID.randomUUID())), stringFactory2, 0); + UpdateDescription description3 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory2, 0); factoryCalls1.set(100); factoryCalls2.set(200); diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt b/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt index 932a464f40..0302fc6db7 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/GroupManagerV2Test_edit.kt @@ -39,9 +39,8 @@ import org.thoughtcrime.securesms.testutil.SystemOutLogger import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI -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.ServiceIds import java.util.UUID @@ -58,9 +57,9 @@ class GroupManagerV2Test_edit { val selfAci: ACI = ACI.from(UUID.randomUUID()) val selfPni: PNI = PNI.from(UUID.randomUUID()) val serviceIds: ServiceIds = ServiceIds(selfAci, selfPni) - val otherSid: ServiceId = ServiceId.from(UUID.randomUUID()) - val selfAndOthers: List = listOf(member(selfAci), member(otherSid)) - val others: List = listOf(member(otherSid)) + val otherAci: ACI = ACI.from(UUID.randomUUID()) + val selfAndOthers: List = listOf(member(selfAci), member(otherAci)) + val others: List = listOf(member(otherAci)) } private lateinit var groupTable: GroupTable @@ -136,13 +135,13 @@ class GroupManagerV2Test_edit { revision = 5, members = listOf( member(selfAci, role = Member.Role.ADMINISTRATOR), - member(otherSid) + member(otherAci) ) ) groupChange(6) { source(selfAci) deleteMember(selfAci) - modifyRole(otherSid, Member.Role.ADMINISTRATOR) + modifyRole(otherAci, Member.Role.ADMINISTRATOR) } } @@ -153,7 +152,7 @@ class GroupManagerV2Test_edit { then { patchedGroup -> assertThat("Revision updated by one", patchedGroup.revision, `is`(6)) assertThat("Self is no longer in the group", patchedGroup.membersList.find { it.uuid == selfAci.toByteString() }, Matchers.nullValue()) - assertThat("Other is now an admin in the group", patchedGroup.membersList.find { it.uuid == otherSid.toByteString() }?.role, `is`(Member.Role.ADMINISTRATOR)) + assertThat("Other is now an admin in the group", patchedGroup.membersList.find { it.uuid == otherAci.toByteString() }?.role, `is`(Member.Role.ADMINISTRATOR)) } } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySetTest.java b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySetTest.java index 1c69223d74..8928b335a8 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySetTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/ProfileKeySetTest.java @@ -5,6 +5,7 @@ import org.signal.core.util.logging.Log; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.testutil.LogRecorder; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.Collections; @@ -40,7 +41,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(editor).addMember(newMember, profileKey).build()); assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty()); - assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ServiceId.from(newMember), profileKey))); + assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey))); } @Test @@ -52,7 +53,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(newMember).addMember(newMember, profileKey).build()); assertTrue(profileKeySet.getProfileKeys().isEmpty()); - assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ServiceId.from(newMember), profileKey))); + assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey))); } @Test @@ -64,7 +65,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(newMember).promote(newMember, profileKey).build()); assertTrue(profileKeySet.getProfileKeys().isEmpty()); - assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ServiceId.from(newMember), profileKey))); + assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey))); } @Test @@ -77,7 +78,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(editor).promote(newMember, profileKey).build()); assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty()); - assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ServiceId.from(newMember), profileKey))); + assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey))); } @Test @@ -89,7 +90,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeByUnknown().promote(newMember, profileKey).build()); assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty()); - assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ServiceId.from(newMember), profileKey))); + assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(newMember), profileKey))); } @Test @@ -101,7 +102,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(member).profileKeyUpdate(member, profileKey).build()); assertTrue(profileKeySet.getProfileKeys().isEmpty()); - assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ServiceId.from(member), profileKey))); + assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey))); } @Test @@ -114,7 +115,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(editor).profileKeyUpdate(member, profileKey).build()); assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty()); - assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ServiceId.from(member), profileKey))); + assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey))); } @Test @@ -129,7 +130,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(editor).profileKeyUpdate(member, profileKey2).build()); assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty()); - assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ServiceId.from(member), profileKey2))); + assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey2))); } @Test @@ -144,7 +145,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(editor).profileKeyUpdate(member, profileKey2).build()); assertTrue(profileKeySet.getProfileKeys().isEmpty()); - assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ServiceId.from(member), profileKey1))); + assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey1))); } @Test @@ -159,7 +160,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(member).profileKeyUpdate(member, profileKey2).build()); assertTrue(profileKeySet.getProfileKeys().isEmpty()); - assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ServiceId.from(member), profileKey2))); + assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(member), profileKey2))); } @Test @@ -186,7 +187,7 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(editor).requestJoin(profileKey).build()); - assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ServiceId.from(editor), profileKey))); + assertThat(profileKeySet.getAuthoritativeProfileKeys(), is(Collections.singletonMap(ACI.from(editor), profileKey))); assertTrue(profileKeySet.getProfileKeys().isEmpty()); } @@ -200,6 +201,6 @@ public final class ProfileKeySetTest { profileKeySet.addKeysFromGroupChange(changeBy(editor).requestJoin(requesting, profileKey).build()); assertTrue(profileKeySet.getAuthoritativeProfileKeys().isEmpty()); - assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ServiceId.from(requesting), profileKey))); + assertThat(profileKeySet.getProfileKeys(), is(Collections.singletonMap(ACI.from(requesting), profileKey))); } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt index 10433cb769..ec3d1e9249 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt @@ -46,9 +46,8 @@ import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger import org.thoughtcrime.securesms.testutil.SystemOutLogger import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api import org.whispersystems.signalservice.api.groupsv2.PartialDecryptedGroup -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI -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.ServiceIds import java.util.UUID @@ -60,9 +59,9 @@ class GroupsV2StateProcessorTest { private val masterKey = GroupMasterKey(fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) private val selfAci: ACI = ACI.from(UUID.randomUUID()) private val serviceIds: ServiceIds = ServiceIds(selfAci, PNI.from(UUID.randomUUID())) - private val otherSid: ServiceId = ServiceId.from(UUID.randomUUID()) - private val selfAndOthers: List = listOf(member(selfAci), member(otherSid)) - private val others: List = listOf(member(otherSid)) + private val otherAci: ACI = ACI.from(UUID.randomUUID()) + private val selfAndOthers: List = listOf(member(selfAci), member(otherAci)) + private val others: List = listOf(member(otherAci)) } private lateinit var groupTable: GroupTable @@ -268,7 +267,7 @@ class GroupsV2StateProcessorTest { revision = 2, title = "Breaking Signal for Science", description = "We break stuff, because we must.", - members = listOf(member(otherSid), member(selfAci, joinedAt = 2)) + members = listOf(member(otherAci), member(selfAci, joinedAt = 2)) ) changeSet { changeLog(2) { @@ -290,7 +289,7 @@ class GroupsV2StateProcessorTest { revision = 3, title = "Breaking Signal for Science", description = "We break stuff, because we must.", - members = listOf(member(otherSid), member(selfAci, joinedAt = 2)) + members = listOf(member(otherAci), member(selfAci, joinedAt = 2)) ) changeSet { changeLog(2) { @@ -346,7 +345,7 @@ class GroupsV2StateProcessorTest { serverState( revision = 3, title = "Beam me up", - members = listOf(member(otherSid), member(selfAci, joinedAt = 3)) + members = listOf(member(otherAci), member(selfAci, joinedAt = 3)) ) changeSet { changeLog(3) { @@ -376,7 +375,7 @@ class GroupsV2StateProcessorTest { serverState( revision = 5, title = "Beam me up!", - members = listOf(member(otherSid), member(selfAci, joinedAt = 3)) + members = listOf(member(otherAci), member(selfAci, joinedAt = 3)) ) changeSet { changeLog(3) { @@ -470,7 +469,7 @@ class GroupsV2StateProcessorTest { */ @Test fun missedMemberAddResolvesWithMultipleRevisionUpdate() { - val secondOther = member(ServiceId.from(UUID.randomUUID())) + val secondOther = member(ACI.from(UUID.randomUUID())) profileAndMessageHelper.masterKey = masterKey @@ -521,7 +520,7 @@ class GroupsV2StateProcessorTest { */ @Test fun missedMemberAddResolvesWithForcedUpdate() { - val secondOther = member(ServiceId.from(UUID.randomUUID())) + val secondOther = member(ACI.from(UUID.randomUUID())) profileAndMessageHelper.masterKey = masterKey diff --git a/app/src/test/java/org/thoughtcrime/securesms/recipients/RecipientIdCacheTest.java b/app/src/test/java/org/thoughtcrime/securesms/recipients/RecipientIdCacheTest.java index 23b84b782f..57479aa402 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/recipients/RecipientIdCacheTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/recipients/RecipientIdCacheTest.java @@ -7,6 +7,7 @@ import org.junit.Before; import org.junit.Test; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.testutil.LogRecorder; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import java.util.Optional; @@ -40,7 +41,7 @@ public final class RecipientIdCacheTest { @Test public void empty_access_by_uuid() { - RecipientId recipientId = recipientIdCache.get(ServiceId.from(UUID.randomUUID()), null); + RecipientId recipientId = recipientIdCache.get(ACI.from(UUID.randomUUID()), null); assertNull(recipientId); } @@ -55,7 +56,7 @@ public final class RecipientIdCacheTest { @Test public void cache_hit_by_uuid() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, null)); @@ -67,8 +68,8 @@ public final class RecipientIdCacheTest { @Test public void cache_miss_by_uuid() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); - ServiceId sid2 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); + ServiceId sid2 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, null)); @@ -80,7 +81,7 @@ public final class RecipientIdCacheTest { @Test public void cache_hit_by_uuid_e164_not_supplied_on_get() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, "+15551234567")); @@ -92,7 +93,7 @@ public final class RecipientIdCacheTest { @Test public void cache_miss_by_uuid_e164_not_supplied_on_put() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, null)); @@ -129,7 +130,7 @@ public final class RecipientIdCacheTest { @Test public void cache_hit_by_e164_uuid_not_supplied_on_get() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, "+15551234567")); @@ -141,7 +142,7 @@ public final class RecipientIdCacheTest { @Test public void cache_miss_by_e164_uuid_not_supplied_on_put() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); String e164 = "+1555123456"; recipientIdCache.put(recipient(recipientId1, null, e164)); @@ -154,7 +155,7 @@ public final class RecipientIdCacheTest { @Test public void cache_hit_by_both() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); String e164 = "+1555123456"; recipientIdCache.put(recipient(recipientId1, sid1, e164)); @@ -167,7 +168,7 @@ public final class RecipientIdCacheTest { @Test public void full_recipient_id_learned_by_two_puts() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); String e164 = "+1555123456"; recipientIdCache.put(recipient(recipientId1, sid1, null)); @@ -182,7 +183,7 @@ public final class RecipientIdCacheTest { public void if_cache_state_disagrees_returns_null() { RecipientId recipientId1 = recipientId(); RecipientId recipientId2 = recipientId(); - ServiceId sid = ServiceId.from(UUID.randomUUID()); + ServiceId sid = ACI.from(UUID.randomUUID()); String e164 = "+1555123456"; recipientIdCache.put(recipient(recipientId1, null, e164)); @@ -200,7 +201,7 @@ public final class RecipientIdCacheTest { public void after_invalid_cache_hit_entries_are_cleared_up() { RecipientId recipientId1 = recipientId(); RecipientId recipientId2 = recipientId(); - ServiceId sid = ServiceId.from(UUID.randomUUID()); + ServiceId sid = ACI.from(UUID.randomUUID()); String e164 = "+1555123456"; recipientIdCache.put(recipient(recipientId1, null, e164)); @@ -216,8 +217,8 @@ public final class RecipientIdCacheTest { public void multiple_entries() { RecipientId recipientId1 = recipientId(); RecipientId recipientId2 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); - ServiceId sid2 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); + ServiceId sid2 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, null)); recipientIdCache.put(recipient(recipientId2, sid2, null)); @@ -229,12 +230,12 @@ public final class RecipientIdCacheTest { @Test public void drops_oldest_when_reaches_cache_limit() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, null)); for (int i = 0; i < TEST_CACHE_LIMIT; i++) { - recipientIdCache.put(recipient(recipientId(), ServiceId.from(UUID.randomUUID()), null)); + recipientIdCache.put(recipient(recipientId(), ACI.from(UUID.randomUUID()), null)); } assertNull(recipientIdCache.get(sid1, null)); @@ -243,17 +244,17 @@ public final class RecipientIdCacheTest { @Test public void remains_in_cache_when_used_before_reaching_cache_limit() { RecipientId recipientId1 = recipientId(); - ServiceId sid1 = ServiceId.from(UUID.randomUUID()); + ServiceId sid1 = ACI.from(UUID.randomUUID()); recipientIdCache.put(recipient(recipientId1, sid1, null)); for (int i = 0; i < TEST_CACHE_LIMIT - 1; i++) { - recipientIdCache.put(recipient(recipientId(), ServiceId.from(UUID.randomUUID()), null)); + recipientIdCache.put(recipient(recipientId(), ACI.from(UUID.randomUUID()), null)); } assertEquals(recipientId1, recipientIdCache.get(sid1, null)); - recipientIdCache.put(recipient(recipientId(), ServiceId.from(UUID.randomUUID()), null)); + recipientIdCache.put(recipient(recipientId(), ACI.from(UUID.randomUUID()), null)); assertEquals(recipientId1, recipientIdCache.get(sid1, null)); } 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 8cf104b635..c754f9bdf6 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/storage/ContactRecordProcessorTest.kt @@ -21,8 +21,8 @@ import org.thoughtcrime.securesms.keyvalue.AccountValues import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.testutil.EmptyLogger import org.thoughtcrime.securesms.util.FeatureFlags -import org.whispersystems.signalservice.api.push.ACI -import org.whispersystems.signalservice.api.push.PNI +import org.whispersystems.signalservice.api.push.ServiceId.ACI +import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.storage.SignalContactRecord import org.whispersystems.signalservice.api.storage.StorageId import org.whispersystems.signalservice.internal.storage.protos.ContactRecord @@ -56,9 +56,9 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServicePni(PNI_B.toString()) - setServiceE164(E164_B) + setAci(ACI_B.toString()) + setPni(PNI_B.toString()) + setE164(E164_B) } // WHEN @@ -74,7 +74,7 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceE164(E164_B) + setE164(E164_B) } // WHEN @@ -90,8 +90,8 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServiceE164(E164_A) + setAci(ACI_B.toString()) + setE164(E164_A) } // WHEN @@ -107,7 +107,7 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_A.toString()) + setAci(ACI_A.toString()) } // WHEN @@ -123,7 +123,7 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(PNI_A.toString()) + setAci(PNI_A.toString()) } // WHEN @@ -139,8 +139,8 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServicePni(PNI_A.toString()) + setAci(ACI_B.toString()) + setPni(PNI_A.toString()) } // WHEN @@ -150,52 +150,14 @@ class ContactRecordProcessorTest { assertTrue(result) } - @Test - fun `isInvalid, pniOnly pnpDisabled, true`() { - // GIVEN - val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - - featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(false) - - val record = buildRecord { - setServiceId(PNI_B.toString()) - setServicePni(PNI_B.toString()) - } - - // WHEN - val result = subject.isInvalid(record) - - // THEN - assertTrue(result) - } - - @Test - fun `isInvalid, pniOnly pnpEnabled, false`() { - // GIVEN - val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) - - featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(true) - - val record = buildRecord { - setServiceId(PNI_B.toString()) - setServicePni(PNI_B.toString()) - } - - // WHEN - val result = subject.isInvalid(record) - - // THEN - assertFalse(result) - } - @Test fun `isInvalid, valid E164, true`() { // GIVEN val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServiceE164(E164_B) + setAci(ACI_B.toString()) + setE164(E164_B) } // WHEN @@ -211,8 +173,8 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServiceE164("15551234567") + setAci(ACI_B.toString()) + setE164("15551234567") } // WHEN @@ -228,8 +190,8 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServiceE164("+1555ABC4567") + setAci(ACI_B.toString()) + setE164("+1555ABC4567") } // WHEN @@ -245,8 +207,8 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServiceE164("+") + setAci(ACI_B.toString()) + setE164("+") } // WHEN @@ -262,8 +224,8 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServiceE164("+12345678901234567890") + setAci(ACI_B.toString()) + setE164("+12345678901234567890") } // WHEN @@ -279,8 +241,8 @@ class ContactRecordProcessorTest { val subject = ContactRecordProcessor(ACI_A, PNI_A, E164_A, recipientTable) val record = buildRecord { - setServiceId(ACI_B.toString()) - setServiceE164("+05551234567") + setAci(ACI_B.toString()) + setE164("+05551234567") } // WHEN @@ -298,22 +260,22 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(true) val local = buildRecord(STORAGE_ID_A) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_A) - setServicePni(PNI_A.toString()) + setAci(ACI_A.toString()) + setE164(E164_A) + setPni(PNI_A.toString()) } val remote = buildRecord(STORAGE_ID_B) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_A) - setServicePni(PNI_B.toString()) + setAci(ACI_A.toString()) + setE164(E164_A) + setPni(PNI_B.toString()) } // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) // THEN - assertEquals(local.serviceId, result.serviceId) + assertEquals(local.aci, result.aci) assertEquals(local.number.get(), result.number.get()) assertEquals(local.pni.get(), result.pni.get()) } @@ -326,22 +288,22 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(true) val local = buildRecord(STORAGE_ID_A) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_A) - setServicePni(PNI_A.toString()) + setAci(ACI_A.toString()) + setE164(E164_A) + setPni(PNI_A.toString()) } val remote = buildRecord(STORAGE_ID_B) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_B) - setServicePni(PNI_A.toString()) + setAci(ACI_A.toString()) + setE164(E164_B) + setPni(PNI_A.toString()) } // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) // THEN - assertEquals(local.serviceId, result.serviceId) + assertEquals(local.aci, result.aci) assertEquals(local.number.get(), result.number.get()) assertEquals(local.pni.get(), result.pni.get()) } @@ -354,22 +316,22 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(true) val local = buildRecord(STORAGE_ID_A) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_A) - setServicePni(PNI_A.toString()) + setAci(ACI_A.toString()) + setE164(E164_A) + setPni(PNI_A.toString()) } val remote = buildRecord(STORAGE_ID_B) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_B) - setServicePni(PNI_B.toString()) + setAci(ACI_A.toString()) + setE164(E164_B) + setPni(PNI_B.toString()) } // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) // THEN - assertEquals(remote.serviceId, result.serviceId) + assertEquals(remote.aci, result.aci) assertEquals(remote.number.get(), result.number.get()) assertEquals(remote.pni.get(), result.pni.get()) } @@ -382,22 +344,22 @@ class ContactRecordProcessorTest { featureFlags.`when` { FeatureFlags.phoneNumberPrivacy() }.thenReturn(false) val local = buildRecord(STORAGE_ID_A) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_A) - setServicePni(PNI_A.toString()) + setAci(ACI_A.toString()) + setE164(E164_A) + setPni(PNI_A.toString()) } val remote = buildRecord(STORAGE_ID_B) { - setServiceId(ACI_A.toString()) - setServiceE164(E164_B) - setServicePni(PNI_B.toString()) + setAci(ACI_A.toString()) + setE164(E164_B) + setPni(PNI_B.toString()) } // WHEN val result = subject.merge(remote, local, TestKeyGenerator(STORAGE_ID_C)) // THEN - assertEquals(remote.serviceId, result.serviceId) + assertEquals(remote.aci, result.aci) assertEquals(remote.number.get(), result.number.get()) assertEquals(false, result.pni.isPresent) } diff --git a/app/src/test/java/org/thoughtcrime/securesms/storage/StorageSyncHelperTest.java b/app/src/test/java/org/thoughtcrime/securesms/storage/StorageSyncHelperTest.java index bbdfc1bf10..3b4fb873af 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/storage/StorageSyncHelperTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/storage/StorageSyncHelperTest.java @@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.storage.StorageSyncHelper.IdDifferenceResult; import org.thoughtcrime.securesms.util.FeatureFlags; import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.storage.SignalAccountRecord; import org.whispersystems.signalservice.api.storage.SignalContactRecord; import org.whispersystems.signalservice.api.storage.SignalGroupV1Record; @@ -40,15 +41,15 @@ import static org.thoughtcrime.securesms.testutil.TestHelpers.byteListOf; public final class StorageSyncHelperTest { - private static final ServiceId SID_A = ServiceId.parseOrThrow("ebef429e-695e-4f51-bcc4-526a60ac68c7"); - private static final ServiceId SID_SELF = ServiceId.parseOrThrow("1b2a2ca5-fc9e-4656-8c9f-22cc349ed3af"); + private static final ACI ACI_A = ACI.parseOrThrow("ebef429e-695e-4f51-bcc4-526a60ac68c7"); + private static final ACI ACI_SELF = ACI.parseOrThrow("1b2a2ca5-fc9e-4656-8c9f-22cc349ed3af"); private static final String E164_A = "+16108675309"; private static final String E164_SELF = "+16105555555"; private static final Recipient SELF = mock(Recipient.class); static { - when(SELF.getServiceId()).thenReturn(Optional.of(SID_SELF)); + when(SELF.getServiceId()).thenReturn(Optional.of(ACI_SELF)); when(SELF.getE164()).thenReturn(Optional.of(E164_SELF)); when(SELF.resolve()).thenReturn(SELF); } @@ -132,8 +133,8 @@ public final class StorageSyncHelperTest { byte[] profileKey = new byte[32]; byte[] profileKeyCopy = profileKey.clone(); - SignalContactRecord a = contactBuilder(1, SID_A, E164_A, "a").setProfileKey(profileKey).build(); - SignalContactRecord b = contactBuilder(1, SID_A, E164_A, "a").setProfileKey(profileKeyCopy).build(); + SignalContactRecord a = contactBuilder(1, ACI_A, E164_A, "a").setProfileKey(profileKey).build(); + SignalContactRecord b = contactBuilder(1, ACI_A, E164_A, "a").setProfileKey(profileKeyCopy).build(); assertEquals(a, b); assertEquals(a.hashCode(), b.hashCode()); @@ -147,8 +148,8 @@ public final class StorageSyncHelperTest { byte[] profileKeyCopy = profileKey.clone(); profileKeyCopy[0] = 1; - SignalContactRecord a = contactBuilder(1, SID_A, E164_A, "a").setProfileKey(profileKey).build(); - SignalContactRecord b = contactBuilder(1, SID_A, E164_A, "a").setProfileKey(profileKeyCopy).build(); + SignalContactRecord a = contactBuilder(1, ACI_A, E164_A, "a").setProfileKey(profileKey).build(); + SignalContactRecord b = contactBuilder(1, ACI_A, E164_A, "a").setProfileKey(profileKeyCopy).build(); assertNotEquals(a, b); assertNotEquals(a.hashCode(), b.hashCode()); @@ -171,7 +172,7 @@ public final class StorageSyncHelperTest { } private static SignalContactRecord.Builder contactBuilder(int key, - ServiceId aci, + ACI aci, String e164, String profileName) { diff --git a/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt b/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt index 29ff559c15..b6ff71b053 100644 --- a/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt +++ b/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt @@ -8,6 +8,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedMember import org.signal.storageservice.protos.groups.local.DecryptedPendingMember import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.util.UuidUtil import org.whispersystems.signalservice.internal.push.SignalServiceProtos import java.util.UUID @@ -30,30 +31,30 @@ fun encryptedGroupContext(masterKey: GroupMasterKey): SignalServiceProtos.GroupC return SignalServiceProtos.GroupContextV2.newBuilder().setMasterKey(ByteString.copyFrom(masterKey.serialize())).build() } -fun DecryptedGroupChange.Builder.addRequestingMember(serviceId: ServiceId) { - addNewRequestingMembers(requestingMember(serviceId)) +fun DecryptedGroupChange.Builder.addRequestingMember(aci: ACI) { + addNewRequestingMembers(requestingMember(aci)) } -fun DecryptedGroupChange.Builder.deleteRequestingMember(serviceId: ServiceId) { - addDeleteRequestingMembers(serviceId.toByteString()) +fun DecryptedGroupChange.Builder.deleteRequestingMember(aci: ACI) { + addDeleteRequestingMembers(aci.toByteString()) } -fun DecryptedGroupChange.Builder.addMember(serviceId: ServiceId) { - addNewMembers(member(serviceId)) +fun DecryptedGroupChange.Builder.addMember(aci: ACI) { + addNewMembers(member(aci)) } fun ServiceId.toByteString(): ByteString { - return UuidUtil.toByteString(uuid()) + return UuidUtil.toByteString(rawUuid) } fun member(serviceId: UUID, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember { - return member(ServiceId.from(serviceId), role, joinedAt) + return member(ACI.from(serviceId), role, joinedAt) } -fun member(serviceId: ServiceId, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember { +fun member(aci: ACI, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember { return DecryptedMember.newBuilder() .setRole(role) - .setUuid(serviceId.toByteString()) + .setUuid(aci.toByteString()) .setJoinedAtRevision(joinedAt) .build() } diff --git a/dependencies.gradle b/dependencies.gradle index 5ef1e5ec1e..eb4caa57a9 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -14,7 +14,7 @@ dependencyResolutionManagement { version('exoplayer', '2.19.0') version('glide', '4.13.2') version('kotlin', '1.8.10') - version('libsignal-client', '0.26.0') + version('libsignal-client', '0.28.1') version('mp4parser', '1.9.39') version('android-gradle-plugin', '8.0.2') version('accompanist', '0.28.0') diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 85a8748577..15f8e75895 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5000,6 +5000,22 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + + + + + + + + + @@ -5008,6 +5024,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + 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 605283f91c..117f73b1fb 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 @@ -33,8 +33,8 @@ 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.ACI; -import org.whispersystems.signalservice.api.push.PNI; +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.exceptions.NoContentException; @@ -740,14 +740,14 @@ public class SignalServiceAccountManager { new ProfileCipherOutputStreamFactory(profileKey)); } - return this.pushServiceSocket.writeProfile(new SignalServiceProfileWrite(profileKey.getProfileKeyVersion(aci.uuid()).serialize(), + return this.pushServiceSocket.writeProfile(new SignalServiceProfileWrite(profileKey.getProfileKeyVersion(aci.getRawUuid()).serialize(), ciphertextName, ciphertextAbout, ciphertextEmoji, ciphertextMobileCoinAddress, avatar.hasAvatar, avatar.keepTheSame, - profileKey.getCommitment(aci.uuid()).serialize(), + profileKey.getCommitment(aci.getRawUuid()).serialize(), visibleBadgeIds), profileAvatarData); } @@ -756,7 +756,7 @@ public class SignalServiceAccountManager { throws NonSuccessfulResponseCodeException, PushNetworkException { try { - ProfileAndCredential credential = this.pushServiceSocket.retrieveVersionedProfileAndCredential(serviceId.uuid(), profileKey, Optional.empty(), locale).get(10, TimeUnit.SECONDS); + ProfileAndCredential credential = this.pushServiceSocket.retrieveVersionedProfileAndCredential(serviceId.getRawUuid(), profileKey, Optional.empty(), locale).get(10, TimeUnit.SECONDS); return credential.getExpiringProfileKeyCredential(); } catch (InterruptedException | TimeoutException e) { throw new PushNetworkException(e); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java index 565f81fe4b..61eda77ff6 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java @@ -100,9 +100,9 @@ public class SignalServiceMessageReceiver { if (profileKey.isPresent()) { if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) { - return socket.retrieveVersionedProfileAndCredential(serviceId.uuid(), profileKey.get(), unidentifiedAccess, locale); + return socket.retrieveVersionedProfileAndCredential(serviceId.getRawUuid(), profileKey.get(), unidentifiedAccess, locale); } else { - return FutureTransformers.map(socket.retrieveVersionedProfile(serviceId.uuid(), profileKey.get(), unidentifiedAccess, locale), profile -> { + return FutureTransformers.map(socket.retrieveVersionedProfile(serviceId.getRawUuid(), profileKey.get(), unidentifiedAccess, locale), profile -> { return new ProfileAndCredential(profile, SignalServiceProfile.RequestType.PROFILE, Optional.empty()); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index b07b1bcb13..10e04f6535 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -65,7 +65,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMes import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.DistributionId; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; @@ -890,7 +890,7 @@ public class SignalServiceMessageSender { byte[] signature = localPniIdentity.signAlternateIdentity(aciStore.getIdentityKeyPair().getPublicKey()); return SignalServiceProtos.PniSignatureMessage.newBuilder() - .setPni(UuidUtil.toByteString(localPni.uuid())) + .setPni(UuidUtil.toByteString(localPni.getRawUuid())) .setSignature(ByteString.copyFrom(signature)) .build(); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java index 81cb50ccc6..3fe1b10b48 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipher.java @@ -47,7 +47,7 @@ import org.whispersystems.signalservice.api.SignalSessionLock; import org.whispersystems.signalservice.api.messages.SignalServiceContent; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.messages.SignalServiceMetadata; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; @@ -102,7 +102,7 @@ public class SignalServiceCipher { PushTransportDetails transport = new PushTransportDetails(); SignalProtocolAddress localProtocolAddress = new SignalProtocolAddress(localAddress.getIdentifier(), localDeviceId); SignalGroupCipher groupCipher = new SignalGroupCipher(sessionLock, new GroupCipher(signalProtocolStore, localProtocolAddress)); - SignalSealedSessionCipher sessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orElse(null), localDeviceId)); + SignalSealedSessionCipher sessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber().orElse(null), localDeviceId)); CiphertextMessage message = groupCipher.encrypt(distributionId.asUuid(), transport.getPaddedMessageBody(unpaddedMessage)); UnidentifiedSenderMessageContent messageContent = new UnidentifiedSenderMessageContent(message, senderCertificate, @@ -119,7 +119,7 @@ public class SignalServiceCipher { { if (unidentifiedAccess.isPresent()) { SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, destination)); - SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orElse(null), localDeviceId)); + SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber().orElse(null), localDeviceId)); return content.processSealedSender(sessionCipher, sealedSessionCipher, destination, unidentifiedAccess.get().getUnidentifiedCertificate()); } else { @@ -231,7 +231,7 @@ public class SignalServiceCipher { paddedMessage = new PlaintextContent(envelope.getContent().toByteArray()).getBody(); metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerTimestamp(), serverDeliveredTimestamp, false, envelope.getServerGuid(), Optional.empty(), envelope.getDestinationServiceId()); } else if (envelope.getType().getNumber() == Envelope.Type.UNIDENTIFIED_SENDER_VALUE) { - SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orElse(null), localDeviceId)); + SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().getRawUuid(), localAddress.getNumber().orElse(null), localDeviceId)); DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, envelope.getContent().toByteArray(), envelope.getServerTimestamp()); SignalServiceAddress resultAddress = new SignalServiceAddress(ACI.parseOrThrow(result.getSenderUuid()), result.getSenderE164()); Optional groupId = result.getGroupId(); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java index c603c652ad..506bb2472a 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Api.java @@ -28,7 +28,6 @@ import org.whispersystems.signalservice.internal.push.exceptions.ForbiddenExcept import java.io.IOException; import java.security.SecureRandom; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -64,7 +63,7 @@ public class GroupsV2Api { throws VerificationFailedException { ClientZkAuthOperations authOperations = groupsOperations.getAuthOperations(); - AuthCredentialWithPni authCredentialWithPni = authOperations.receiveAuthCredentialWithPni(aci.uuid(), pni.uuid(), redemptionTimeSeconds, authCredentialWithPniResponse); + AuthCredentialWithPni authCredentialWithPni = authOperations.receiveAuthCredentialWithPni(aci.getRawUuid(), pni.getRawUuid(), redemptionTimeSeconds, authCredentialWithPniResponse); AuthCredentialPresentation authCredentialPresentation = authOperations.createAuthCredentialPresentation(new SecureRandom(), groupSecretParams, authCredentialWithPni); return new GroupsV2AuthorizationString(groupSecretParams, authCredentialPresentation); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java index 1516483d62..e1988b45ac 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2Operations.java @@ -39,6 +39,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember; import org.signal.storageservice.protos.groups.local.DecryptedString; import org.signal.storageservice.protos.groups.local.DecryptedTimer; import org.signal.storageservice.protos.groups.local.EnabledState; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -989,7 +990,7 @@ public final class GroupsV2Operations { GroupChange.Actions.AddMemberAction addMember = addMembers.get(i); ProfileKeyCredentialPresentation profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(addMember.getAdded().getPresentation().toByteArray()); - ids.add(ServiceId.from(clientZkGroupCipher.decryptUuid(profileKeyCredentialPresentation.getUuidCiphertext()))); + ids.add(ACI.from(clientZkGroupCipher.decryptUuid(profileKeyCredentialPresentation.getUuidCiphertext()))); } return ids; } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceContent.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceContent.java index 6115f2dae5..8a9bd9f2ce 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceContent.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceContent.java @@ -46,7 +46,8 @@ import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMes import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.payments.Money; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.storage.StorageKey; @@ -538,7 +539,7 @@ public final class SignalServiceContent { return groupId; } - public String getDestinationUuid() { + public String getDestinationServiceId() { return destinationUuid; } @@ -869,9 +870,9 @@ public final class SignalServiceContent { List readMessages = new LinkedList<>(); for (SignalServiceProtos.SyncMessage.Read read : content.getReadList()) { - ServiceId serviceId = ServiceId.parseOrNull(read.getSenderAci()); - if (serviceId != null) { - readMessages.add(new ReadMessage(serviceId, read.getTimestamp())); + ACI aci = ACI.parseOrNull(read.getSenderAci()); + if (aci != null) { + readMessages.add(new ReadMessage(aci, read.getTimestamp())); } else { Log.w(TAG, "Encountered an invalid ReadMessage! Ignoring."); } @@ -884,9 +885,9 @@ public final class SignalServiceContent { List viewedMessages = new LinkedList<>(); for (SignalServiceProtos.SyncMessage.Viewed viewed : content.getViewedList()) { - ServiceId serviceId = ServiceId.parseOrNull(viewed.getSenderAci()); - if (serviceId != null) { - viewedMessages.add(new ViewedMessage(serviceId, viewed.getTimestamp())); + ACI aci = ACI.parseOrNull(viewed.getSenderAci()); + if (aci != null) { + viewedMessages.add(new ViewedMessage(aci, viewed.getTimestamp())); } else { Log.w(TAG, "Encountered an invalid ReadMessage! Ignoring."); } @@ -896,9 +897,9 @@ public final class SignalServiceContent { } if (content.hasViewOnceOpen()) { - ServiceId serviceId = ServiceId.parseOrNull(content.getViewOnceOpen().getSenderAci()); - if (serviceId != null) { - ViewOnceOpenMessage timerRead = new ViewOnceOpenMessage(serviceId, content.getViewOnceOpen().getTimestamp()); + ACI aci = ACI.parseOrNull(content.getViewOnceOpen().getSenderAci()); + if (aci != null) { + ViewOnceOpenMessage timerRead = new ViewOnceOpenMessage(aci, content.getViewOnceOpen().getTimestamp()); return SignalServiceSyncMessage.forViewOnceOpen(timerRead); } else { throw new InvalidMessageStructureException("ViewOnceOpen message has no sender!"); @@ -1021,9 +1022,9 @@ public final class SignalServiceContent { if (content.getMessageRequestResponse().hasGroupId()) { responseMessage = MessageRequestResponseMessage.forGroup(content.getMessageRequestResponse().getGroupId().toByteArray(), type); } else { - ServiceId serviceId = ServiceId.parseOrNull(content.getMessageRequestResponse().getThreadAci()); - if (serviceId != null) { - responseMessage = MessageRequestResponseMessage.forIndividual(serviceId, type); + ACI aci = ACI.parseOrNull(content.getMessageRequestResponse().getThreadAci()); + if (aci != null) { + responseMessage = MessageRequestResponseMessage.forIndividual(aci, type); } else { throw new InvalidMessageStructureException("Message request response has an invalid thread identifier!"); } @@ -1194,7 +1195,7 @@ public final class SignalServiceContent { attachment.hasThumbnail() ? createAttachmentPointer(attachment.getThumbnail()) : null)); } - ServiceId author = ServiceId.parseOrNull(content.getQuote().getAuthorAci()); + ACI author = ACI.parseOrNull(content.getQuote().getAuthorAci()); if (author != null) { return new SignalServiceDataMessage.Quote(content.getQuote().getId(), author, @@ -1305,17 +1306,17 @@ public final class SignalServiceContent { return null; } - SignalServiceProtos.DataMessage.Reaction reaction = content.getReaction(); - ServiceId serviceId = ServiceId.parseOrNull(reaction.getTargetAuthorAci()); + SignalServiceProtos.DataMessage.Reaction reaction = content.getReaction(); + ACI aci = ACI.parseOrNull(reaction.getTargetAuthorAci()); - if (serviceId == null) { + if (aci == null) { Log.w(TAG, "Cannot parse author UUID on reaction"); return null; } return new SignalServiceDataMessage.Reaction(reaction.getEmoji(), reaction.getRemove(), - serviceId, + aci, reaction.getTargetSentTimestamp()); } @@ -1361,13 +1362,13 @@ public final class SignalServiceContent { return null; } - ServiceId serviceId = ServiceId.parseOrNull(content.getStoryContext().getAuthorAci()); + ACI aci = ACI.parseOrNull(content.getStoryContext().getAuthorAci()); - if (serviceId == null) { + if (aci == null) { throw new InvalidMessageStructureException("Invalid author ACI!"); } - return new SignalServiceDataMessage.StoryContext(serviceId, content.getStoryContext().getSentTimestamp()); + return new SignalServiceDataMessage.StoryContext(aci, content.getStoryContext().getSentTimestamp()); } private static @Nullable SignalServiceDataMessage.GiftBadge createGiftBadge(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceEnvelope.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceEnvelope.java index 590ae6a8e8..e011a7cda2 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceEnvelope.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceEnvelope.java @@ -169,13 +169,6 @@ public class SignalServiceEnvelope { return envelope.getSourceDevice(); } - /** - * @return The envelope's sender as a SignalServiceAddress. - */ - public SignalServiceAddress getSourceAddress() { - return new SignalServiceAddress(ServiceId.parseOrNull(envelope.getSourceServiceId())); - } - /** * @return The envelope content type. */ @@ -286,7 +279,7 @@ public class SignalServiceEnvelope { .setStory(isStory()); if (getSourceServiceId().isPresent()) { - builder.setSourceUuid(getSourceServiceId().get()); + builder.setSourceServiceId(getSourceServiceId().get()); } if (hasContent()) { @@ -298,7 +291,7 @@ public class SignalServiceEnvelope { } if (hasDestinationUuid()) { - builder.setDestinationUuid(getDestinationServiceId()); + builder.setDestinationServiceId(getDestinationServiceId()); } if (hasReportingToken()) { @@ -322,7 +315,7 @@ public class SignalServiceEnvelope { Preconditions.checkNotNull(proto); - ServiceId sourceServiceId = proto.hasSourceUuid() ? ServiceId.parseOrNull(proto.getSourceUuid()) : null; + ServiceId sourceServiceId = proto.hasSourceServiceId() ? ServiceId.parseOrNull(proto.getSourceServiceId()) : null; return new SignalServiceEnvelope(proto.getType(), sourceServiceId != null ? Optional.of(new SignalServiceAddress(sourceServiceId)) : Optional.empty(), @@ -332,7 +325,7 @@ public class SignalServiceEnvelope { proto.getServerReceivedTimestamp(), proto.getServerDeliveredTimestamp(), proto.getServerGuid(), - proto.getDestinationUuid(), + proto.getDestinationServiceId(), proto.getUrgent(), proto.getStory(), proto.hasReportingToken() ? proto.getReportingToken().toByteArray() : null); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServicePniSignatureMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServicePniSignatureMessage.java index c53fd13d92..c2aeb67358 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServicePniSignatureMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServicePniSignatureMessage.java @@ -1,7 +1,7 @@ package org.whispersystems.signalservice.api.messages; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; /** * When someone sends a message to your PNI, you need to attach one of these PNI signature messages, diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ACI.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ACI.java deleted file mode 100644 index f8f9dc0bbc..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ACI.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.whispersystems.signalservice.api.push; - -import com.google.protobuf.ByteString; - -import org.whispersystems.signalservice.api.util.UuidUtil; - -import java.util.UUID; - -/** - * An ACI is an "Account Identity". They're just UUIDs, but given multiple different things could be UUIDs, this wrapper exists to give us type safety around - * this *specific type* of UUID. - */ -public final class ACI extends ServiceId { - - public static ACI from(UUID uuid) { - return new ACI(uuid); - } - - public static ACI from(ServiceId serviceId) { - return new ACI(serviceId.uuid()); - } - - public static ACI fromNullable(ServiceId serviceId) { - return serviceId != null ? new ACI(serviceId.uuid()) : null; - } - - public static ACI parseOrThrow(String raw) { - return from(UUID.fromString(raw)); - } - - public static ACI parseOrNull(String raw) { - UUID uuid = UuidUtil.parseOrNull(raw); - return uuid != null ? from(uuid) : null; - } - - private ACI(UUID uuid) { - super(uuid); - } - - public ByteString toByteString() { - return UuidUtil.toByteString(uuid); - } - - public byte[] toByteArray() { - return UuidUtil.toByteArray(uuid); - } -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/PNI.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/PNI.java deleted file mode 100644 index 407791b033..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/PNI.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.whispersystems.signalservice.api.push; - -import org.whispersystems.signalservice.api.util.UuidUtil; - -import java.util.UUID; - -/** - * A PNI is a "Phone Number Identity". They're just UUIDs, but given multiple different things could be UUIDs, this wrapper exists to give us type safety around - * this *specific type* of UUID. - */ -public final class PNI extends ServiceId { - - public static PNI from(UUID uuid) { - return new PNI(uuid); - } - - public static PNI parseOrNull(String raw) { - UUID uuid = UuidUtil.parseOrNull(raw); - return uuid != null ? from(uuid) : null; - } - - public static PNI parseOrThrow(String raw) { - return from(UUID.fromString(raw)); - } - - public static PNI parseOrThrow(byte[] raw) { - return from(UuidUtil.parseOrThrow(raw)); - } - - public static PNI parseOrNull(byte[] raw) { - UUID uuid = UuidUtil.parseOrNull(raw); - return uuid != null ? from(uuid) : null; - } - - private PNI(UUID uuid) { - super(uuid); - } -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.java deleted file mode 100644 index 946fe2265c..0000000000 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.whispersystems.signalservice.api.push; - -import com.google.protobuf.ByteString; - -import org.signal.libsignal.protocol.SignalProtocolAddress; -import org.whispersystems.signalservice.api.util.UuidUtil; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.UUID; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - -/** - * A wrapper around a UUID that represents an identifier for an account. Today, that is either an {@link ACI} or a {@link PNI}. - * However, that doesn't mean every {@link ServiceId} is an instance of one of those classes. In reality, we often - * do not know which we have. And it shouldn't really matter. - * - * The only times you truly know, and the only times you should actually care, is during CDS refreshes or specific inbound messages - * that link them together. - */ -public class ServiceId { - - public static final ServiceId UNKNOWN = ServiceId.from(UuidUtil.UNKNOWN_UUID); - - protected final UUID uuid; - - protected ServiceId(UUID uuid) { - this.uuid = uuid; - } - - public static ServiceId from(UUID uuid) { - return new ServiceId(uuid); - } - - public static ServiceId parseOrThrow(String raw) { - return from(UUID.fromString(raw)); - } - - public static ServiceId parseOrThrow(byte[] raw) { - return from(UuidUtil.parseOrThrow(raw)); - } - - public static @Nullable ServiceId parseOrNull(String raw) { - UUID uuid = UuidUtil.parseOrNull(raw); - return uuid != null ? from(uuid) : null; - } - - public static ServiceId parseOrNull(byte[] raw) { - UUID uuid = UuidUtil.parseOrNull(raw); - return uuid != null ? from(uuid) : null; - } - - public static ServiceId parseOrUnknown(String raw) { - ServiceId aci = parseOrNull(raw); - return aci != null ? aci : UNKNOWN; - } - - public static ServiceId fromByteString(ByteString bytes) { - return parseOrThrow(bytes.toByteArray()); - } - - public static ServiceId fromByteStringOrNull(ByteString bytes) { - UUID uuid = UuidUtil.fromByteStringOrNull(bytes); - return uuid != null ? from(uuid) : null; - } - - public static ServiceId fromByteStringOrUnknown(ByteString bytes) { - ServiceId uuid = fromByteStringOrNull(bytes); - return uuid != null ? uuid : UNKNOWN; - } - - public UUID uuid() { - return uuid; - } - - public boolean isUnknown() { - return uuid.equals(UNKNOWN.uuid); - } - - public boolean isValid() { - return !isUnknown(); - } - - public SignalProtocolAddress toProtocolAddress(int deviceId) { - return new SignalProtocolAddress(uuid.toString(), deviceId); - } - - public ByteString toByteString() { - return UuidUtil.toByteString(uuid); - } - - public byte[] toByteArray() { - return UuidUtil.toByteArray(uuid); - } - - public static List filterKnown(Collection serviceIds) { - return serviceIds.stream().filter(sid -> !sid.equals(UNKNOWN)).collect(Collectors.toList()); - } - - @Override - public String toString() { - return uuid.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ServiceId)) return false; - final ServiceId serviceId = (ServiceId) o; - return Objects.equals(uuid, serviceId.uuid); - } - - @Override - public int hashCode() { - return uuid.hashCode(); - } -} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt new file mode 100644 index 0000000000..fc0a433f38 --- /dev/null +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt @@ -0,0 +1,181 @@ +package org.whispersystems.signalservice.api.push + +import com.google.protobuf.ByteString +import org.signal.libsignal.protocol.ServiceId.InvalidServiceIdException +import org.signal.libsignal.protocol.SignalProtocolAddress +import org.whispersystems.signalservice.api.util.UuidUtil +import java.lang.IllegalArgumentException +import java.util.UUID +import kotlin.jvm.Throws +import org.signal.libsignal.protocol.ServiceId as LibSignalServiceId +import org.signal.libsignal.protocol.ServiceId.Aci as LibSignalAci +import org.signal.libsignal.protocol.ServiceId.Pni as LibSignalPni + +/** + * A wrapper around a UUID that represents an identifier for an account. Today, that is either an [ACI] or a [PNI]. + * However, that doesn't mean every [ServiceId] is an *instance* of one of those classes. In reality, we often + * do not know which we have. And it shouldn't really matter. + * + * The only times you truly know, and the only times you should actually care, is during CDS refreshes or specific inbound messages + * that link them together. + */ +sealed class ServiceId(@JvmField protected val libsignalServiceId: LibSignalServiceId) { + companion object { + /** Parses a ServiceId serialized as a string. Returns null if the ServiceId is invalid. */ + @JvmStatic + fun parseOrNull(raw: String?): ServiceId? { + if (raw == null) { + return null + } + + return try { + when (val serviceId = LibSignalServiceId.parseFromString(raw)) { + is LibSignalAci -> ACI(serviceId) + is LibSignalPni -> PNI(serviceId) + else -> null + } + } catch (e: IllegalArgumentException) { + null + } catch (e: InvalidServiceIdException) { + null + } + } + + /** Parses a ServiceId serialized as a byte array. Returns null if the ServiceId is invalid. */ + @JvmStatic + fun parseOrNull(raw: ByteArray?): ServiceId? { + if (raw == null) { + return null + } + + return try { + return when (val serviceId = LibSignalServiceId.parseFromBinary(raw)) { + is LibSignalAci -> ACI.from(serviceId.rawUUID) + is LibSignalPni -> PNI.from(serviceId.rawUUID) + else -> null + } + } catch (e: IllegalArgumentException) { + null + } catch (e: InvalidServiceIdException) { + null + } + } + + /** Parses a ServiceId serialized as a string. Crashes if the ServiceId is invalid. */ + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(raw: String): ServiceId = parseOrNull(raw) ?: throw IllegalArgumentException("Invalid ServiceId!") + + /** Parses a ServiceId serialized as a byte array. Crashes if the ServiceId is invalid. */ + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(raw: ByteArray): ServiceId = parseOrNull(raw) ?: throw IllegalArgumentException("Invalid ServiceId!") + + /** Parses a ServiceId serialized as a ByteString. Crashes if the ServiceId is invalid. */ + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(bytes: ByteString): ServiceId = parseOrThrow(bytes.toByteArray()) + } + + val rawUuid: UUID = libsignalServiceId.rawUUID + + val isUnknown: Boolean = rawUuid == UuidUtil.UNKNOWN_UUID + + val isValid: Boolean = !isUnknown + + fun toProtocolAddress(deviceId: Int): SignalProtocolAddress = SignalProtocolAddress(libsignalServiceId.toServiceIdString(), deviceId) + + fun toByteString(): ByteString = ByteString.copyFrom(libsignalServiceId.toServiceIdBinary()) + + fun toByteArray(): ByteArray = libsignalServiceId.toServiceIdBinary() + + fun logString(): String = libsignalServiceId.toLogString() + + /** + * A serialized string that can be parsed via [parseOrThrow], for instance. + * Basically ACI's are just normal UUIDs, and PNI's are UUIDs with a `PNI:` prefix. + */ + override fun toString(): String = libsignalServiceId.toServiceIdString() + + data class ACI(val libsignalAci: LibSignalAci) : ServiceId(libsignalAci) { + companion object { + @JvmField + val UNKNOWN = from(UuidUtil.UNKNOWN_UUID) + + @JvmStatic + fun from(uuid: UUID): ACI = ACI(LibSignalAci(uuid)) + + @JvmStatic + fun parseOrNull(raw: String?): ACI? = ServiceId.parseOrNull(raw).let { if (it is ACI) it else null } + + @JvmStatic + fun parseOrNull(raw: ByteArray?): ACI? = ServiceId.parseOrNull(raw).let { if (it is ACI) it else null } + + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(raw: String?): ACI = parseOrNull(raw) ?: throw IllegalArgumentException("Invalid ACI!") + + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(raw: ByteArray?): ACI = parseOrNull(raw) ?: throw IllegalArgumentException("Invalid ACI!") + + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(bytes: ByteString): ACI = parseOrThrow(bytes.toByteArray()) + + @JvmStatic + fun parseOrUnknown(bytes: ByteString?): ACI = UuidUtil.fromByteStringOrNull(bytes)?.let { from(it) } ?: UNKNOWN + + @JvmStatic + fun parseOrUnknown(raw: String?): ACI = parseOrNull(raw) ?: UNKNOWN + } + + override fun toString(): String = super.toString() + } + + data class PNI(private val libsignalPni: LibSignalPni) : ServiceId(libsignalPni) { + companion object { + @JvmField + var UNKNOWN = from(UuidUtil.UNKNOWN_UUID) + + @JvmStatic + fun from(uuid: UUID): PNI = PNI(LibSignalPni(uuid)) + + @JvmStatic + fun parseOrNull(raw: String?): PNI? = ServiceId.parseOrNull(raw).let { if (it is PNI) it else null } + + /** Parses a plain UUID (without the `PNI:` prefix) as a PNI. Be certain that whatever you pass to this is for sure a PNI! */ + @JvmStatic + fun parseUnPrefixedOrNull(raw: String?): PNI? { + val uuid = UuidUtil.parseOrNull(raw) + return if (uuid != null) { + PNI(LibSignalPni(uuid)) + } else { + null + } + } + + @JvmStatic + fun parseOrNull(raw: ByteArray?): PNI? = ServiceId.parseOrNull(raw).let { if (it is PNI) it else null } + + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(raw: String?): PNI = parseOrNull(raw) ?: throw IllegalArgumentException("Invalid PNI!") + + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(raw: ByteArray?): PNI = parseOrNull(raw) ?: throw IllegalArgumentException("Invalid PNI!") + + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseOrThrow(bytes: ByteString): PNI = parseOrThrow(bytes.toByteArray()) + + /** Parses a plain UUID (without the `PNI:` prefix) as a PNI. Be certain that whatever you pass to this is for sure a PNI! */ + @JvmStatic + @Throws(IllegalArgumentException::class) + fun parseUnPrefixedOrThrow(raw: String?): PNI = parseUnPrefixedOrNull(raw) ?: throw IllegalArgumentException("Invalid PNI!") + } + + override fun toString(): String = super.toString() + } +} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java index 22d2676575..a905564255 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIds.java @@ -2,7 +2,8 @@ package org.whispersystems.signalservice.api.push; import com.google.protobuf.ByteString; -import org.whispersystems.signalservice.api.util.UuidUtil; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import java.util.Objects; import java.util.UUID; @@ -37,7 +38,7 @@ public final class ServiceIds { } public boolean matches(UUID uuid) { - return uuid.equals(aci.uuid()) || (pni != null && uuid.equals(pni.uuid())); + return uuid.equals(aci.getRawUuid()) || (pni != null && uuid.equals(pni.getRawUuid())); } public boolean matches(ByteString uuid) { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/CdsiV2Service.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/CdsiV2Service.java index 0f8c7acee3..1e9f22d10d 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/CdsiV2Service.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/CdsiV2Service.java @@ -7,8 +7,8 @@ import org.signal.cdsi.proto.ClientResponse; import org.signal.libsignal.protocol.util.ByteUtil; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +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.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -130,7 +130,7 @@ public final class CdsiV2Service { for (Map.Entry entry : serviceIds.entrySet()) { try { - os.write(UuidUtil.toByteArray(entry.getKey().uuid())); + os.write(UuidUtil.toByteArray(entry.getKey().getRawUuid())); os.write(UnidentifiedAccess.deriveAccessKeyFrom(entry.getValue())); } catch (IOException e) { throw new AssertionError("Failed to write long to ByteString", e); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/ProfileService.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/ProfileService.java index 6ab6fcc30f..550d4cc00e 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/ProfileService.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/services/ProfileService.java @@ -81,11 +81,11 @@ public final class ProfileService { .setVerb("GET"); if (profileKey.isPresent()) { - ProfileKeyVersion profileKeyIdentifier = profileKey.get().getProfileKeyVersion(serviceId.uuid()); + ProfileKeyVersion profileKeyIdentifier = profileKey.get().getProfileKeyVersion(serviceId.getRawUuid()); String version = profileKeyIdentifier.serialize(); if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) { - requestContext = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, serviceId.uuid(), profileKey.get()); + requestContext = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, serviceId.getRawUuid(), profileKey.get()); ProfileKeyCredentialRequest request = requestContext.getRequest(); String credentialRequest = Hex.toStringCondensed(request.serialize()); 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 c4cb2f7c03..84332a360e 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 @@ -382,11 +382,11 @@ public final class SignalAccountRecord implements SignalRecord { static PinnedConversation fromRemote(AccountRecord.PinnedConversation remote) { if (remote.hasContact()) { - ServiceId serviceId = ServiceId.parseOrNull(remote.getContact().getUuid()); + ServiceId serviceId = ServiceId.parseOrNull(remote.getContact().getServiceId()); if (serviceId != null) { return forContact(new SignalServiceAddress(serviceId, remote.getContact().getE164())); } else { - Log.w(TAG, "Bad serviceId on pinned contact! Length: " + remote.getContact().getUuid()); + Log.w(TAG, "Bad serviceId on pinned contact! Length: " + remote.getContact().getServiceId()); return PinnedConversation.forEmpty(); } } else if (!remote.getLegacyGroupId().isEmpty()) { @@ -418,7 +418,7 @@ public final class SignalAccountRecord implements SignalRecord { if (contact.isPresent()) { AccountRecord.PinnedConversation.Contact.Builder contactBuilder = AccountRecord.PinnedConversation.Contact.newBuilder(); - contactBuilder.setUuid(contact.get().getServiceId().toString()); + contactBuilder.setServiceId(contact.get().getServiceId().toString()); if (contact.get().getNumber().isPresent()) { contactBuilder.setE164(contact.get().getNumber().get()); 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 1e9e0c0da3..ebeb5bed7a 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 @@ -4,7 +4,8 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import org.signal.libsignal.protocol.logging.Log; -import org.whispersystems.signalservice.api.push.PNI; +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; @@ -25,7 +26,7 @@ public final class SignalContactRecord implements SignalRecord { private final ContactRecord proto; private final boolean hasUnknownFields; - private final ServiceId serviceId; + private final ACI aci; private final Optional pni; private final Optional e164; private final Optional profileGivenName; @@ -38,13 +39,12 @@ public final class SignalContactRecord implements SignalRecord { private final Optional identityKey; public SignalContactRecord(StorageId id, ContactRecord proto) { - this.id = id; - this.proto = proto; - this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); - - this.serviceId = ServiceId.parseOrUnknown(proto.getServiceId()); - this.pni = OptionalUtil.absentIfEmpty(proto.getServicePni()).map(PNI::parseOrNull); - this.e164 = OptionalUtil.absentIfEmpty(proto.getServiceE164()); + this.id = id; + this.proto = proto; + this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); + this.aci = ACI.parseOrUnknown(proto.getAci()); + this.pni = OptionalUtil.absentIfEmpty(proto.getPni()).map(PNI::parseOrNull); + this.e164 = OptionalUtil.absentIfEmpty(proto.getE164()); this.profileGivenName = OptionalUtil.absentIfEmpty(proto.getGivenName()); this.profileFamilyName = OptionalUtil.absentIfEmpty(proto.getFamilyName()); this.systemGivenName = OptionalUtil.absentIfEmpty(proto.getSystemGivenName()); @@ -75,8 +75,8 @@ public final class SignalContactRecord implements SignalRecord { diff.add("ID"); } - if (!Objects.equals(this.getServiceId(), that.getServiceId())) { - diff.add("ServiceId"); + if (!Objects.equals(this.getAci(), that.getAci())) { + diff.add("ACI"); } if (!Objects.equals(this.getPni(), that.getPni())) { @@ -173,8 +173,8 @@ public final class SignalContactRecord implements SignalRecord { return hasUnknownFields ? proto.toByteArray() : null; } - public ServiceId getServiceId() { - return serviceId; + public ACI getAci() { + return aci; } public Optional getPni() { @@ -257,7 +257,7 @@ public final class SignalContactRecord implements SignalRecord { * 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().clearServicePni().build()); + return new SignalContactRecord(id, proto.toBuilder().clearPni().build()); } public ContactRecord toProto() { @@ -282,7 +282,7 @@ public final class SignalContactRecord implements SignalRecord { private final StorageId id; private final ContactRecord.Builder builder; - public Builder(byte[] rawId, ServiceId serviceId, byte[] serializedUnknowns) { + public Builder(byte[] rawId, ACI aci, byte[] serializedUnknowns) { this.id = StorageId.forContact(rawId); if (serializedUnknowns != null) { @@ -291,16 +291,16 @@ public final class SignalContactRecord implements SignalRecord { this.builder = ContactRecord.newBuilder(); } - builder.setServiceId(serviceId.toString()); + builder.setAci(aci.toString()); } public Builder setE164(String e164) { - builder.setServiceE164(e164 == null ? "" : e164); + builder.setE164(e164 == null ? "" : e164); return this; } public Builder setPni(PNI pni) { - builder.setServicePni(pni == null ? "" : pni.toString()); + builder.setPni(pni == null ? "" : pni.toString()); return this; } 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 df3e526a15..986d822e84 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 @@ -28,7 +28,7 @@ public class SignalStoryDistributionListRecord implements SignalRecord { this.id = id; this.proto = proto; this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); - this.recipients = proto.getRecipientUuidsList() + this.recipients = proto.getRecipientServiceIdsList() .stream() .map(ServiceId::parseOrNull) .filter(Objects::nonNull) @@ -157,10 +157,10 @@ public class SignalStoryDistributionListRecord implements SignalRecord { } public Builder setRecipients(List recipients) { - builder.clearRecipientUuids(); - builder.addAllRecipientUuids(recipients.stream() - .map(SignalServiceAddress::getIdentifier) - .collect(Collectors.toList())); + builder.clearRecipientServiceIds(); + builder.addAllRecipientServiceIds(recipients.stream() + .map(SignalServiceAddress::getIdentifier) + .collect(Collectors.toList())); return this; } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/CredentialsProvider.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/CredentialsProvider.java index 256f4aeae3..5ffae1bef5 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/CredentialsProvider.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/util/CredentialsProvider.java @@ -6,8 +6,8 @@ package org.whispersystems.signalservice.api.util; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; public interface CredentialsProvider { ACI getAci(); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/IdentityCheckResponse.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/IdentityCheckResponse.java index 42515e7676..252dce3f39 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/IdentityCheckResponse.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/IdentityCheckResponse.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.signal.libsignal.protocol.IdentityKey; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.internal.util.JsonUtil; import java.util.List; 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 7a4fe6622f..5a33de0359 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 @@ -55,7 +55,7 @@ import org.whispersystems.signalservice.api.payments.CurrencyConversions; import org.whispersystems.signalservice.api.profiles.ProfileAndCredential; import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.whispersystems.signalservice.api.profiles.SignalServiceProfileWrite; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceIdType; import org.whispersystems.signalservice.api.push.SignalServiceAddress; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/SendGroupMessageResponse.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/SendGroupMessageResponse.java index 25110f3573..75ca6668f0 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/SendGroupMessageResponse.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/SendGroupMessageResponse.java @@ -12,6 +12,7 @@ public class SendGroupMessageResponse { private static final String TAG = SendGroupMessageResponse.class.getSimpleName(); + // Contains serialized ServiceIds @JsonProperty private String[] uuids404; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/JsonUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/JsonUtil.java index 4e809491d6..9478d063aa 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/JsonUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/JsonUtil.java @@ -24,7 +24,7 @@ import org.signal.libsignal.protocol.IdentityKey; import org.signal.libsignal.protocol.InvalidKeyException; import org.signal.libsignal.protocol.logging.Log; import org.whispersystems.signalservice.api.kbs.MasterKey; -import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.exceptions.MalformedResponseException; import org.whispersystems.signalservice.api.util.UuidUtil; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/StaticCredentialsProvider.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/StaticCredentialsProvider.java index 4a211f9f6c..57ca633b99 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/StaticCredentialsProvider.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/util/StaticCredentialsProvider.java @@ -6,8 +6,8 @@ package org.whispersystems.signalservice.internal.util; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; +import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.util.CredentialsProvider; public class StaticCredentialsProvider implements CredentialsProvider { diff --git a/libsignal/service/src/main/proto/InternalSerialization.proto b/libsignal/service/src/main/proto/InternalSerialization.proto index b3f9df0f63..7138f129e7 100644 --- a/libsignal/service/src/main/proto/InternalSerialization.proto +++ b/libsignal/service/src/main/proto/InternalSerialization.proto @@ -23,7 +23,7 @@ message SignalServiceContentProto { message SignalServiceEnvelopeProto { optional int32 type = 1; - optional string sourceUuid = 2; + optional string sourceServiceId = 2; reserved /*sourceE164*/ 3; optional int32 deviceId = 4; reserved /*legacyMessage*/ 5; @@ -32,7 +32,7 @@ message SignalServiceEnvelopeProto { optional int64 serverReceivedTimestamp = 8; optional int64 serverDeliveredTimestamp = 9; optional string serverGuid = 10; - optional string destinationUuid = 11; + optional string destinationServiceId = 11; optional bool urgent = 12 [default = true]; optional bool story = 13; optional bytes reportingToken = 14; diff --git a/libsignal/service/src/main/proto/StorageService.proto b/libsignal/service/src/main/proto/StorageService.proto index 049886e3b7..3c050ae778 100644 --- a/libsignal/service/src/main/proto/StorageService.proto +++ b/libsignal/service/src/main/proto/StorageService.proto @@ -79,9 +79,9 @@ message ContactRecord { UNVERIFIED = 2; } - string serviceId = 1; - string serviceE164 = 2; - string servicePni = 15; + string aci = 1; + string e164 = 2; + string pni = 15; bytes profileKey = 3; bytes identityKey = 4; IdentityState identityState = 5; @@ -145,8 +145,8 @@ message AccountRecord { message PinnedConversation { message Contact { - string uuid = 1; - string e164 = 2; + string serviceId = 1; + string e164 = 2; } oneof identifier { @@ -192,10 +192,10 @@ message AccountRecord { } message StoryDistributionListRecord { - bytes identifier = 1; - string name = 2; - repeated string recipientUuids = 3; - uint64 deletedAtTimestamp = 4; - bool allowsReplies = 5; - bool isBlockList = 6; + bytes identifier = 1; + string name = 2; + repeated string recipientServiceIds = 3; + uint64 deletedAtTimestamp = 4; + bool allowsReplies = 5; + bool isBlockList = 6; } diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStreamTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStreamTest.java index a16a92c0d2..b4a4a35800 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStreamTest.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactsInputStreamTest.java @@ -6,6 +6,7 @@ import org.signal.libsignal.protocol.ecc.Curve; import org.signal.libsignal.protocol.ecc.ECKeyPair; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.profiles.ProfileKey; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.internal.util.Util; @@ -24,8 +25,8 @@ public class DeviceContactsInputStreamTest { public void read() throws IOException, InvalidInputException { ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); DeviceContactsOutputStream output = new DeviceContactsOutputStream(byteArrayOut); - SignalServiceAddress addressFirst = new SignalServiceAddress(ServiceId.from(UUID.randomUUID()), "+1404555555"); - SignalServiceAddress addressSecond = new SignalServiceAddress(ServiceId.from(UUID.randomUUID()), "+1444555555"); + SignalServiceAddress addressFirst = new SignalServiceAddress(ACI.from(UUID.randomUUID()), "+1404555555"); + SignalServiceAddress addressSecond = new SignalServiceAddress(ACI.from(UUID.randomUUID()), "+1444555555"); DeviceContact first = new DeviceContact( addressFirst, diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/storage/SignalContactRecordTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/storage/SignalContactRecordTest.java index 63a71c4723..23d8dc0349 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/api/storage/SignalContactRecordTest.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/api/storage/SignalContactRecordTest.java @@ -2,22 +2,23 @@ package org.whispersystems.signalservice.api.storage; import org.junit.Test; import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; public class SignalContactRecordTest { - private static final ServiceId SID_A = ServiceId.parseOrThrow("ebef429e-695e-4f51-bcc4-526a60ac68c7"); - private static final String E164_A = "+16108675309"; + private static final ACI ACI_A = ACI.parseOrThrow("ebef429e-695e-4f51-bcc4-526a60ac68c7"); + private static final String E164_A = "+16108675309"; @Test public void contacts_with_same_identity_key_contents_are_equal() { byte[] profileKey = new byte[32]; byte[] profileKeyCopy = profileKey.clone(); - SignalContactRecord a = contactBuilder(1, SID_A, E164_A, "a").setIdentityKey(profileKey).build(); - SignalContactRecord b = contactBuilder(1, SID_A, E164_A, "a").setIdentityKey(profileKeyCopy).build(); + SignalContactRecord a = contactBuilder(1, ACI_A, E164_A, "a").setIdentityKey(profileKey).build(); + SignalContactRecord b = contactBuilder(1, ACI_A, E164_A, "a").setIdentityKey(profileKeyCopy).build(); assertEquals(a, b); assertEquals(a.hashCode(), b.hashCode()); @@ -29,8 +30,8 @@ public class SignalContactRecordTest { byte[] profileKeyCopy = profileKey.clone(); profileKeyCopy[0] = 1; - SignalContactRecord a = contactBuilder(1, SID_A, E164_A, "a").setIdentityKey(profileKey).build(); - SignalContactRecord b = contactBuilder(1, SID_A, E164_A, "a").setIdentityKey(profileKeyCopy).build(); + SignalContactRecord a = contactBuilder(1, ACI_A, E164_A, "a").setIdentityKey(profileKey).build(); + SignalContactRecord b = contactBuilder(1, ACI_A, E164_A, "a").setIdentityKey(profileKeyCopy).build(); assertNotEquals(a, b); assertNotEquals(a.hashCode(), b.hashCode()); @@ -46,7 +47,7 @@ public class SignalContactRecordTest { } private static SignalContactRecord.Builder contactBuilder(int key, - ServiceId serviceId, + ACI serviceId, String e164, String givenName) { diff --git a/libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java b/libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java index 4903a180bc..4aebc44e40 100644 --- a/libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java +++ b/libsignal/service/src/test/java/org/whispersystems/signalservice/internal/serialize/SignalServiceAddressProtobufSerializerTest.java @@ -2,6 +2,7 @@ package org.whispersystems.signalservice.internal.serialize; import org.junit.Test; import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.internal.serialize.protos.AddressProto; @@ -14,7 +15,7 @@ public final class SignalServiceAddressProtobufSerializerTest { @Test public void serialize_and_deserialize_uuid_address() { - SignalServiceAddress address = new SignalServiceAddress(ServiceId.from(UUID.randomUUID()), Optional.empty()); + SignalServiceAddress address = new SignalServiceAddress(ACI.from(UUID.randomUUID()), Optional.empty()); AddressProto addressProto = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.toProtobuf(address); SignalServiceAddress deserialized = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.fromProtobuf(addressProto); @@ -23,7 +24,7 @@ public final class SignalServiceAddressProtobufSerializerTest { @Test public void serialize_and_deserialize_both_address() { - SignalServiceAddress address = new SignalServiceAddress(ServiceId.from(UUID.randomUUID()), Optional.of("+15552345678")); + SignalServiceAddress address = new SignalServiceAddress(ACI.from(UUID.randomUUID()), Optional.of("+15552345678")); AddressProto addressProto = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.toProtobuf(address); SignalServiceAddress deserialized = org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer.fromProtobuf(addressProto); diff --git a/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt b/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt index 5c6df8ee78..09607c72cd 100644 --- a/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt +++ b/microbenchmark/src/androidTest/java/org/signal/util/SignalClient.kt @@ -20,7 +20,7 @@ import org.whispersystems.signalservice.api.crypto.ContentHint import org.whispersystems.signalservice.api.crypto.EnvelopeContent import org.whispersystems.signalservice.api.crypto.SignalServiceCipher import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess -import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.internal.push.OutgoingPushMessage import org.whispersystems.signalservice.internal.push.SignalServiceProtos @@ -41,7 +41,7 @@ class SignalClient { private val trustRoot: ECKeyPair = Curve.generateKeyPair() } - private val serviceId: ServiceId = ServiceId.from(UUID.randomUUID()) + private val aci: ACI = ACI.from(UUID.randomUUID()) private val store: SignalServiceAccountDataStore = InMemorySignalServiceAccountDataStore() @@ -60,21 +60,21 @@ class SignalClient { private val senderCertificate: SenderCertificate = createCertificateFor( trustRoot = trustRoot, - uuid = serviceId.uuid(), + uuid = aci.rawUuid, e164 = "+${Random.nextLong(1111111111L, 9999999999L)}", deviceId = 1, identityKey = store.identityKeyPair.publicKey.publicKey, expires = Long.MAX_VALUE ) - private val cipher = SignalServiceCipher(SignalServiceAddress(serviceId), 1, store, TestSessionLock(), CertificateValidator(trustRoot.publicKey)) + private val cipher = SignalServiceCipher(SignalServiceAddress(aci), 1, store, TestSessionLock(), CertificateValidator(trustRoot.publicKey)) /** * Sets up sessions using the [to] client's [preKeyBundle]. Note that you can only initialize a client once * since we currently only make a single prekey bundle. */ fun initializeSession(to: SignalClient) { - val address = SignalProtocolAddress(to.serviceId.toString(), 1) + val address = SignalProtocolAddress(to.aci.toString(), 1) SessionBuilder(store, address).process(to.preKeyBundle) } @@ -91,7 +91,7 @@ class SignalClient { .build() val outgoingPushMessage: OutgoingPushMessage = cipher.encrypt( - SignalProtocolAddress(to.serviceId.toString(), 1), + SignalProtocolAddress(to.aci.toString(), 1), Optional.empty(), EnvelopeContent.encrypted(content, ContentHint.RESENDABLE, Optional.empty()) ) @@ -99,9 +99,9 @@ class SignalClient { val encryptedContent: ByteArray = Base64.decode(outgoingPushMessage.content) return SignalServiceProtos.Envelope.newBuilder() - .setSourceServiceId(serviceId.toString()) + .setSourceServiceId(aci.toString()) .setSourceDevice(1) - .setDestinationServiceId(to.serviceId.toString()) + .setDestinationServiceId(to.aci.toString()) .setTimestamp(sentTimestamp) .setServerTimestamp(sentTimestamp) .setServerGuid(UUID.randomUUID().toString()) @@ -124,7 +124,7 @@ class SignalClient { .build() val outgoingPushMessage: OutgoingPushMessage = cipher.encrypt( - SignalProtocolAddress(to.serviceId.toString(), 1), + SignalProtocolAddress(to.aci.toString(), 1), Optional.of(UnidentifiedAccess(to.unidentifiedAccessKey, senderCertificate.serialized, false)), EnvelopeContent.encrypted(content, ContentHint.RESENDABLE, Optional.empty()) ) @@ -132,9 +132,9 @@ class SignalClient { val encryptedContent: ByteArray = Base64.decode(outgoingPushMessage.content) return SignalServiceProtos.Envelope.newBuilder() - .setSourceServiceId(serviceId.toString()) + .setSourceServiceId(aci.toString()) .setSourceDevice(1) - .setDestinationServiceId(to.serviceId.toString()) + .setDestinationServiceId(to.aci.toString()) .setTimestamp(sentTimestamp) .setServerTimestamp(sentTimestamp) .setServerGuid(UUID.randomUUID().toString())