Inline the RecipientMergeV2 flag.
This commit is contained in:
parent
367ff7c75c
commit
62d5777c39
5 changed files with 44 additions and 812 deletions
|
@ -46,7 +46,7 @@ import java.util.Optional
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
class RecipientDatabaseTest_getAndPossiblyMerge {
|
||||||
|
|
||||||
private lateinit var recipientDatabase: RecipientDatabase
|
private lateinit var recipientDatabase: RecipientDatabase
|
||||||
private lateinit var identityDatabase: IdentityDatabase
|
private lateinit var identityDatabase: IdentityDatabase
|
||||||
|
@ -93,7 +93,7 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
/** If all you have is an ACI, you can just store that, regardless of trust level. */
|
/** If all you have is an ACI, you can just store that, regardless of trust level. */
|
||||||
@Test
|
@Test
|
||||||
fun getAndPossiblyMerge_aciAndE164MapToNoOne_aciOnly() {
|
fun getAndPossiblyMerge_aciAndE164MapToNoOne_aciOnly() {
|
||||||
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, null)
|
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, null)
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
val recipient = Recipient.resolved(recipientId)
|
||||||
assertEquals(ACI_A, recipient.requireServiceId())
|
assertEquals(ACI_A, recipient.requireServiceId())
|
||||||
|
@ -103,7 +103,7 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
/** If all you have is an E164, you can just store that, regardless of trust level. */
|
/** If all you have is an E164, you can just store that, regardless of trust level. */
|
||||||
@Test
|
@Test
|
||||||
fun getAndPossiblyMerge_aciAndE164MapToNoOne_e164Only() {
|
fun getAndPossiblyMerge_aciAndE164MapToNoOne_e164Only() {
|
||||||
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(null, E164_A)
|
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(null, E164_A)
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
val recipient = Recipient.resolved(recipientId)
|
||||||
assertEquals(E164_A, recipient.requireE164())
|
assertEquals(E164_A, recipient.requireE164())
|
||||||
|
@ -113,7 +113,7 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
/** With high trust, you can associate an ACI-e164 pair. */
|
/** With high trust, you can associate an ACI-e164 pair. */
|
||||||
@Test
|
@Test
|
||||||
fun getAndPossiblyMerge_aciAndE164MapToNoOne_aciAndE164() {
|
fun getAndPossiblyMerge_aciAndE164MapToNoOne_aciAndE164() {
|
||||||
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
val recipient = Recipient.resolved(recipientId)
|
||||||
assertEquals(ACI_A, recipient.requireServiceId())
|
assertEquals(ACI_A, recipient.requireServiceId())
|
||||||
|
@ -129,7 +129,7 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164() {
|
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164() {
|
||||||
val existingId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
|
val existingId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingId, retrievedId)
|
assertEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -140,9 +140,9 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
/** Basically the ‘change number’ case. Update the existing user. */
|
/** Basically the ‘change number’ case. Update the existing user. */
|
||||||
@Test
|
@Test
|
||||||
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164_2() {
|
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164_2() {
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val existingId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_B)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_B)
|
||||||
assertEquals(existingId, retrievedId)
|
assertEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -159,7 +159,7 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
fun getAndPossiblyMerge_e164MapsToExistingUserButAciDoesNot_aciAndE164() {
|
fun getAndPossiblyMerge_e164MapsToExistingUserButAciDoesNot_aciAndE164() {
|
||||||
val existingId: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A)
|
val existingId: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingId, retrievedId)
|
assertEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -170,10 +170,10 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
/** We never change the ACI of an existing row. New ACI = new person. Take the e164 from the current holder. */
|
/** We never change the ACI of an existing row. New ACI = new person. Take the e164 from the current holder. */
|
||||||
@Test
|
@Test
|
||||||
fun getAndPossiblyMerge_e164MapsToExistingUserButAciDoesNot_aciAndE164_2() {
|
fun getAndPossiblyMerge_e164MapsToExistingUserButAciDoesNot_aciAndE164_2() {
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val existingId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
recipientDatabase.setPni(existingId, PNI_A)
|
recipientDatabase.setPni(existingId, PNI_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_B, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_B, E164_A)
|
||||||
recipientDatabase.setPni(retrievedId, PNI_A)
|
recipientDatabase.setPni(retrievedId, PNI_A)
|
||||||
assertNotEquals(existingId, retrievedId)
|
assertNotEquals(existingId, retrievedId)
|
||||||
|
|
||||||
|
@ -195,9 +195,9 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
}
|
}
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val existingId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_B, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_B, E164_A)
|
||||||
assertNotEquals(existingId, retrievedId)
|
assertNotEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -216,9 +216,9 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
/** If your ACI and e164 match, you’re good. */
|
/** If your ACI and e164 match, you’re good. */
|
||||||
@Test
|
@Test
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164() {
|
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164() {
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val existingId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingId, retrievedId)
|
assertEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -232,10 +232,10 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
val changeNumberListener = ChangeNumberListener()
|
val changeNumberListener = ChangeNumberListener()
|
||||||
changeNumberListener.enqueue()
|
changeNumberListener.enqueue()
|
||||||
|
|
||||||
val existingAciId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, null)
|
val existingAciId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, null)
|
||||||
val existingE164Id: RecipientId = recipientDatabase.getAndPossiblyMergePnp(null, E164_A)
|
val existingE164Id: RecipientId = recipientDatabase.getAndPossiblyMerge(null, E164_A)
|
||||||
|
|
||||||
val mergedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val mergedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingAciId, mergedId)
|
assertEquals(existingAciId, mergedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(mergedId)
|
val retrievedRecipient = Recipient.resolved(mergedId)
|
||||||
|
@ -255,10 +255,10 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
val changeNumberListener = ChangeNumberListener()
|
val changeNumberListener = ChangeNumberListener()
|
||||||
changeNumberListener.enqueue()
|
changeNumberListener.enqueue()
|
||||||
|
|
||||||
val existingAciId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_B)
|
val existingAciId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_B)
|
||||||
val existingE164Id: RecipientId = recipientDatabase.getAndPossiblyMergePnp(null, E164_A)
|
val existingE164Id: RecipientId = recipientDatabase.getAndPossiblyMerge(null, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingAciId, retrievedId)
|
assertEquals(existingAciId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -278,10 +278,10 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
val changeNumberListener = ChangeNumberListener()
|
val changeNumberListener = ChangeNumberListener()
|
||||||
changeNumberListener.enqueue()
|
changeNumberListener.enqueue()
|
||||||
|
|
||||||
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_B)
|
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_B)
|
||||||
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_B, E164_A)
|
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_B, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingId1, retrievedId)
|
assertEquals(existingId1, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -302,10 +302,10 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_mergeAndPhoneNumberChange() {
|
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_mergeAndPhoneNumberChange() {
|
||||||
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_B)
|
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_B)
|
||||||
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMergePnp(null, E164_A)
|
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMerge(null, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingId1, retrievedId)
|
assertEquals(existingId1, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -327,10 +327,10 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
}
|
}
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
||||||
|
|
||||||
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_B, E164_A)
|
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_B, E164_A)
|
||||||
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, null)
|
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, null)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
assertEquals(existingId2, retrievedId)
|
assertEquals(existingId2, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -351,9 +351,9 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
}
|
}
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val existingId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_B, changeSelf = false)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_B, changeSelf = false)
|
||||||
assertEquals(existingId, retrievedId)
|
assertEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -370,9 +370,9 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
}
|
}
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val existingId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_B, changeSelf = true)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_B, changeSelf = true)
|
||||||
assertEquals(existingId, retrievedId)
|
assertEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -386,9 +386,9 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
val changeNumberListener = ChangeNumberListener()
|
val changeNumberListener = ChangeNumberListener()
|
||||||
changeNumberListener.enqueue()
|
changeNumberListener.enqueue()
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A)
|
val existingId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A)
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_B)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_B)
|
||||||
assertEquals(existingId, retrievedId)
|
assertEquals(existingId, retrievedId)
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
val retrievedRecipient = Recipient.resolved(retrievedId)
|
||||||
|
@ -446,7 +446,7 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
val distributionListId: DistributionListId = distributionListDatabase.createList("testlist", listOf(recipientIdE164, recipientIdAciB))!!
|
val distributionListId: DistributionListId = distributionListDatabase.createList("testlist", listOf(recipientIdE164, recipientIdAciB))!!
|
||||||
|
|
||||||
// Merge
|
// Merge
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergePnp(ACI_A, E164_A, true)
|
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, true)
|
||||||
val retrievedThreadId: Long = threadDatabase.getThreadIdFor(retrievedId)!!
|
val retrievedThreadId: Long = threadDatabase.getThreadIdFor(retrievedId)!!
|
||||||
assertEquals(recipientIdAci, retrievedId)
|
assertEquals(recipientIdAci, retrievedId)
|
||||||
|
|
||||||
|
@ -573,7 +573,7 @@ class RecipientDatabaseTest_getAndPossiblyMergePnp {
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class)
|
@Test(expected = IllegalArgumentException::class)
|
||||||
fun getAndPossiblyMerge_noArgs_invalid() {
|
fun getAndPossiblyMerge_noArgs_invalid() {
|
||||||
recipientDatabase.getAndPossiblyMergePnp(null, null, true)
|
recipientDatabase.getAndPossiblyMerge(null, null, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureDbEmpty() {
|
private fun ensureDbEmpty() {
|
|
@ -1,661 +0,0 @@
|
||||||
package org.thoughtcrime.securesms.database
|
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
||||||
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.assertNotEquals
|
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.signal.core.util.CursorUtil
|
|
||||||
import org.signal.core.util.ThreadUtil
|
|
||||||
import org.signal.libsignal.protocol.IdentityKey
|
|
||||||
import org.signal.libsignal.protocol.SignalProtocolAddress
|
|
||||||
import org.signal.libsignal.protocol.state.SessionRecord
|
|
||||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey
|
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup
|
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedMember
|
|
||||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListId
|
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListRecord
|
|
||||||
import org.thoughtcrime.securesms.database.model.Mention
|
|
||||||
import org.thoughtcrime.securesms.database.model.MessageId
|
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
|
||||||
import org.thoughtcrime.securesms.database.model.ReactionRecord
|
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
|
||||||
import org.thoughtcrime.securesms.jobs.RecipientChangedNumberJob
|
|
||||||
import org.thoughtcrime.securesms.keyvalue.AccountValues
|
|
||||||
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet
|
|
||||||
import org.thoughtcrime.securesms.keyvalue.KeyValueStore
|
|
||||||
import org.thoughtcrime.securesms.keyvalue.MockKeyValuePersistentStorage
|
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
|
||||||
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.IncomingTextMessage
|
|
||||||
import org.whispersystems.signalservice.api.push.ACI
|
|
||||||
import org.whispersystems.signalservice.api.push.PNI
|
|
||||||
import org.whispersystems.signalservice.api.util.UuidUtil
|
|
||||||
import java.util.Optional
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
|
||||||
class RecipientDatabaseTest_getAndPossiblyMergeLegacy {
|
|
||||||
|
|
||||||
private lateinit var recipientDatabase: RecipientDatabase
|
|
||||||
private lateinit var identityDatabase: IdentityDatabase
|
|
||||||
private lateinit var groupReceiptDatabase: GroupReceiptDatabase
|
|
||||||
private lateinit var groupDatabase: GroupDatabase
|
|
||||||
private lateinit var threadDatabase: ThreadDatabase
|
|
||||||
private lateinit var smsDatabase: MessageDatabase
|
|
||||||
private lateinit var mmsDatabase: MessageDatabase
|
|
||||||
private lateinit var sessionDatabase: SessionDatabase
|
|
||||||
private lateinit var mentionDatabase: MentionDatabase
|
|
||||||
private lateinit var reactionDatabase: ReactionDatabase
|
|
||||||
private lateinit var notificationProfileDatabase: NotificationProfileDatabase
|
|
||||||
private lateinit var distributionListDatabase: DistributionListDatabase
|
|
||||||
|
|
||||||
private val localAci = ACI.from(UUID.randomUUID())
|
|
||||||
private val localPni = PNI.from(UUID.randomUUID())
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
recipientDatabase = SignalDatabase.recipients
|
|
||||||
recipientDatabase = SignalDatabase.recipients
|
|
||||||
identityDatabase = SignalDatabase.identities
|
|
||||||
groupReceiptDatabase = SignalDatabase.groupReceipts
|
|
||||||
groupDatabase = SignalDatabase.groups
|
|
||||||
threadDatabase = SignalDatabase.threads
|
|
||||||
smsDatabase = SignalDatabase.sms
|
|
||||||
mmsDatabase = SignalDatabase.mms
|
|
||||||
sessionDatabase = SignalDatabase.sessions
|
|
||||||
mentionDatabase = SignalDatabase.mentions
|
|
||||||
reactionDatabase = SignalDatabase.reactions
|
|
||||||
notificationProfileDatabase = SignalDatabase.notificationProfiles
|
|
||||||
distributionListDatabase = SignalDatabase.distributionLists
|
|
||||||
|
|
||||||
ensureDbEmpty()
|
|
||||||
|
|
||||||
SignalStore.account().setAci(localAci)
|
|
||||||
SignalStore.account().setPni(localPni)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============================================================
|
|
||||||
// If both the ACI and E164 map to no one
|
|
||||||
// ==============================================================
|
|
||||||
|
|
||||||
/** If all you have is an ACI, you can just store that, regardless of trust level. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciAndE164MapToNoOne_aciOnly() {
|
|
||||||
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, null)
|
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
|
||||||
assertEquals(ACI_A, recipient.requireServiceId())
|
|
||||||
assertFalse(recipient.hasE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** If all you have is an E164, you can just store that, regardless of trust level. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciAndE164MapToNoOne_e164Only() {
|
|
||||||
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(null, E164_A)
|
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
|
||||||
assertEquals(E164_A, recipient.requireE164())
|
|
||||||
assertFalse(recipient.hasServiceId())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** With high trust, you can associate an ACI-e164 pair. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciAndE164MapToNoOne_aciAndE164() {
|
|
||||||
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
|
||||||
assertEquals(ACI_A, recipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, recipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============================================================
|
|
||||||
// If the ACI maps to an existing user, but the E164 doesn't
|
|
||||||
// ==============================================================
|
|
||||||
|
|
||||||
/** You can associate an e164 with an existing ACI. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164() {
|
|
||||||
val existingId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Basically the ‘change number’ case. Update the existing user. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164_2() {
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_B)
|
|
||||||
assertEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_B, retrievedRecipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============================================================
|
|
||||||
// If the E164 maps to an existing user, but the ACI doesn't
|
|
||||||
// ==============================================================
|
|
||||||
|
|
||||||
/** You can associate an e164 with an existing ACI. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_e164MapsToExistingUserButAciDoesNot_aciAndE164() {
|
|
||||||
val existingId: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** We never change the ACI of an existing row. New ACI = new person. Take the e164 from the current holder. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_e164MapsToExistingUserButAciDoesNot_aciAndE164_2() {
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
recipientDatabase.setPni(existingId, PNI_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_B, E164_A)
|
|
||||||
recipientDatabase.setPni(retrievedId, PNI_A)
|
|
||||||
assertNotEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_B, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
|
|
||||||
val existingRecipient = Recipient.resolved(existingId)
|
|
||||||
assertEquals(ACI_A, existingRecipient.requireServiceId())
|
|
||||||
assertFalse(existingRecipient.hasE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** We never want to remove the e164 of our own contact entry. Leave the e164 alone. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_e164MapsToExistingUserButAciDoesNot_e164BelongsToLocalUser() {
|
|
||||||
val dataSet = KeyValueDataSet().apply {
|
|
||||||
putString(AccountValues.KEY_E164, E164_A)
|
|
||||||
putString(AccountValues.KEY_ACI, ACI_A.toString())
|
|
||||||
}
|
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_B, E164_A)
|
|
||||||
assertNotEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_B, retrievedRecipient.requireServiceId())
|
|
||||||
assertFalse(retrievedRecipient.hasE164())
|
|
||||||
|
|
||||||
val existingRecipient = Recipient.resolved(existingId)
|
|
||||||
assertEquals(ACI_A, existingRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, existingRecipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============================================================
|
|
||||||
// If both the ACI and E164 map to an existing user
|
|
||||||
// ==============================================================
|
|
||||||
|
|
||||||
/** If your ACI and e164 match, you’re good. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164() {
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Merge two different users into one. You should prefer the ACI user. Not shown: merging threads, dropping e164 sessions, etc. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_merge() {
|
|
||||||
val changeNumberListener = ChangeNumberListener()
|
|
||||||
changeNumberListener.enqueue()
|
|
||||||
|
|
||||||
val existingAciId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, null)
|
|
||||||
val existingE164Id: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(null, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingAciId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
|
|
||||||
val existingE164Recipient = Recipient.resolved(existingE164Id)
|
|
||||||
assertEquals(retrievedId, existingE164Recipient.id)
|
|
||||||
|
|
||||||
changeNumberListener.waitForJobManager()
|
|
||||||
assertFalse(changeNumberListener.numberChangeWasEnqueued)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Same as [getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_merge], but with a number change. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_merge_changedNumber() {
|
|
||||||
val changeNumberListener = ChangeNumberListener()
|
|
||||||
changeNumberListener.enqueue()
|
|
||||||
|
|
||||||
val existingAciId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_B)
|
|
||||||
val existingE164Id: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(null, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingAciId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
|
|
||||||
val existingE164Recipient = Recipient.resolved(existingE164Id)
|
|
||||||
assertEquals(retrievedId, existingE164Recipient.id)
|
|
||||||
|
|
||||||
changeNumberListener.waitForJobManager()
|
|
||||||
assert(changeNumberListener.numberChangeWasEnqueued)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** No new rules here, just a more complex scenario to show how different rules interact. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_complex() {
|
|
||||||
val changeNumberListener = ChangeNumberListener()
|
|
||||||
changeNumberListener.enqueue()
|
|
||||||
|
|
||||||
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_B)
|
|
||||||
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_B, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingId1, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
|
|
||||||
val existingRecipient2 = Recipient.resolved(existingId2)
|
|
||||||
assertEquals(ACI_B, existingRecipient2.requireServiceId())
|
|
||||||
assertFalse(existingRecipient2.hasE164())
|
|
||||||
|
|
||||||
changeNumberListener.waitForJobManager()
|
|
||||||
assert(changeNumberListener.numberChangeWasEnqueued)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Another case that results in a merge. Nothing strictly new here, but this case is called out because it’s a merge but *also* an E164 change,
|
|
||||||
* which clients may need to know for UX purposes.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_mergeAndPhoneNumberChange() {
|
|
||||||
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_B)
|
|
||||||
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(null, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingId1, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
|
|
||||||
assertFalse(recipientDatabase.getByE164(E164_B).isPresent)
|
|
||||||
|
|
||||||
val recipientWithId2 = Recipient.resolved(existingId2)
|
|
||||||
assertEquals(retrievedId, recipientWithId2.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** We never want to remove the e164 of our own contact entry. Leave the e164 alone. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_e164BelongsToLocalUser() {
|
|
||||||
val dataSet = KeyValueDataSet().apply {
|
|
||||||
putString(AccountValues.KEY_E164, E164_A)
|
|
||||||
putString(AccountValues.KEY_ACI, ACI_B.toString())
|
|
||||||
}
|
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
|
||||||
|
|
||||||
val existingId1: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_B, E164_A)
|
|
||||||
val existingId2: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, null)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
assertEquals(existingId2, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertFalse(retrievedRecipient.hasE164())
|
|
||||||
|
|
||||||
val recipientWithId1 = Recipient.resolved(existingId1)
|
|
||||||
assertEquals(ACI_B, recipientWithId1.requireServiceId())
|
|
||||||
assertEquals(E164_A, recipientWithId1.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This is a case where normally we'd update the E164 of a user, but here the changeSelf flag is disabled, so we shouldn't. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciBelongsToLocalUser_changeSelfFalse() {
|
|
||||||
val dataSet = KeyValueDataSet().apply {
|
|
||||||
putString(AccountValues.KEY_E164, E164_A)
|
|
||||||
putString(AccountValues.KEY_ACI, ACI_A.toString())
|
|
||||||
}
|
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_B, changeSelf = false)
|
|
||||||
assertEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This is a case where we're changing our own number, and it's allowed because changeSelf = true. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciBelongsToLocalUser_changeSelfTrue() {
|
|
||||||
val dataSet = KeyValueDataSet().apply {
|
|
||||||
putString(AccountValues.KEY_E164, E164_A)
|
|
||||||
putString(AccountValues.KEY_ACI, ACI_A.toString())
|
|
||||||
}
|
|
||||||
SignalStore.inject(KeyValueStore(MockKeyValuePersistentStorage.withDataSet(dataSet)))
|
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_B, changeSelf = true)
|
|
||||||
assertEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_B, retrievedRecipient.requireE164())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Verifying a case where a change number job is expected to be enqueued. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_changedNumber() {
|
|
||||||
val changeNumberListener = ChangeNumberListener()
|
|
||||||
changeNumberListener.enqueue()
|
|
||||||
|
|
||||||
val existingId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A)
|
|
||||||
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_B)
|
|
||||||
assertEquals(existingId, retrievedId)
|
|
||||||
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_B, retrievedRecipient.requireE164())
|
|
||||||
|
|
||||||
changeNumberListener.waitForJobManager()
|
|
||||||
assert(changeNumberListener.numberChangeWasEnqueued)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** High trust lets you merge two different users into one. You should prefer the ACI user. Not shown: merging threads, dropping e164 sessions, etc. */
|
|
||||||
@Test
|
|
||||||
fun getAndPossiblyMerge_merge_general() {
|
|
||||||
// Setup
|
|
||||||
val recipientIdAci: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
|
|
||||||
val recipientIdE164: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A)
|
|
||||||
val recipientIdAciB: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_B)
|
|
||||||
|
|
||||||
val smsId1: Long = smsDatabase.insertMessageInbox(smsMessage(sender = recipientIdAci, time = 0, body = "0")).get().messageId
|
|
||||||
val smsId2: Long = smsDatabase.insertMessageInbox(smsMessage(sender = recipientIdE164, time = 1, body = "1")).get().messageId
|
|
||||||
val smsId3: Long = smsDatabase.insertMessageInbox(smsMessage(sender = recipientIdAci, time = 2, body = "2")).get().messageId
|
|
||||||
|
|
||||||
val mmsId1: Long = mmsDatabase.insertSecureDecryptedMessageInbox(mmsMessage(sender = recipientIdAci, time = 3, body = "3"), -1).get().messageId
|
|
||||||
val mmsId2: Long = mmsDatabase.insertSecureDecryptedMessageInbox(mmsMessage(sender = recipientIdE164, time = 4, body = "4"), -1).get().messageId
|
|
||||||
val mmsId3: Long = mmsDatabase.insertSecureDecryptedMessageInbox(mmsMessage(sender = recipientIdAci, time = 5, body = "5"), -1).get().messageId
|
|
||||||
|
|
||||||
val threadIdAci: Long = threadDatabase.getThreadIdFor(recipientIdAci)!!
|
|
||||||
val threadIdE164: Long = threadDatabase.getThreadIdFor(recipientIdE164)!!
|
|
||||||
assertNotEquals(threadIdAci, threadIdE164)
|
|
||||||
|
|
||||||
mentionDatabase.insert(threadIdAci, mmsId1, listOf(Mention(recipientIdE164, 0, 1)))
|
|
||||||
mentionDatabase.insert(threadIdE164, mmsId2, listOf(Mention(recipientIdAci, 0, 1)))
|
|
||||||
|
|
||||||
groupReceiptDatabase.insert(listOf(recipientIdAci, recipientIdE164), mmsId1, 0, 3)
|
|
||||||
|
|
||||||
val identityKeyAci: IdentityKey = identityKey(1)
|
|
||||||
val identityKeyE164: IdentityKey = identityKey(2)
|
|
||||||
|
|
||||||
identityDatabase.saveIdentity(ACI_A.toString(), recipientIdAci, identityKeyAci, IdentityDatabase.VerifiedStatus.VERIFIED, false, 0, false)
|
|
||||||
identityDatabase.saveIdentity(E164_A, recipientIdE164, identityKeyE164, IdentityDatabase.VerifiedStatus.VERIFIED, false, 0, false)
|
|
||||||
|
|
||||||
sessionDatabase.store(localAci, SignalProtocolAddress(ACI_A.toString(), 1), SessionRecord())
|
|
||||||
|
|
||||||
reactionDatabase.addReaction(MessageId(smsId1, false), ReactionRecord("a", recipientIdAci, 1, 1))
|
|
||||||
reactionDatabase.addReaction(MessageId(mmsId1, true), ReactionRecord("b", recipientIdE164, 1, 1))
|
|
||||||
|
|
||||||
val profile1: NotificationProfile = notificationProfile(name = "Test")
|
|
||||||
val profile2: NotificationProfile = notificationProfile(name = "Test2")
|
|
||||||
|
|
||||||
notificationProfileDatabase.addAllowedRecipient(profileId = profile1.id, recipientId = recipientIdAci)
|
|
||||||
notificationProfileDatabase.addAllowedRecipient(profileId = profile1.id, recipientId = recipientIdE164)
|
|
||||||
notificationProfileDatabase.addAllowedRecipient(profileId = profile2.id, recipientId = recipientIdE164)
|
|
||||||
notificationProfileDatabase.addAllowedRecipient(profileId = profile2.id, recipientId = recipientIdAciB)
|
|
||||||
|
|
||||||
val distributionListId: DistributionListId = distributionListDatabase.createList("testlist", listOf(recipientIdE164, recipientIdAciB))!!
|
|
||||||
|
|
||||||
// Merge
|
|
||||||
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMergeLegacy(ACI_A, E164_A, true)
|
|
||||||
val retrievedThreadId: Long = threadDatabase.getThreadIdFor(retrievedId)!!
|
|
||||||
assertEquals(recipientIdAci, retrievedId)
|
|
||||||
|
|
||||||
// Recipient validation
|
|
||||||
val retrievedRecipient = Recipient.resolved(retrievedId)
|
|
||||||
assertEquals(ACI_A, retrievedRecipient.requireServiceId())
|
|
||||||
assertEquals(E164_A, retrievedRecipient.requireE164())
|
|
||||||
|
|
||||||
val existingE164Recipient = Recipient.resolved(recipientIdE164)
|
|
||||||
assertEquals(retrievedId, existingE164Recipient.id)
|
|
||||||
|
|
||||||
// Thread validation
|
|
||||||
assertEquals(threadIdAci, retrievedThreadId)
|
|
||||||
Assert.assertNull(threadDatabase.getThreadIdFor(recipientIdE164))
|
|
||||||
Assert.assertNull(threadDatabase.getThreadRecord(threadIdE164))
|
|
||||||
|
|
||||||
// SMS validation
|
|
||||||
val sms1: MessageRecord = smsDatabase.getMessageRecord(smsId1)!!
|
|
||||||
val sms2: MessageRecord = smsDatabase.getMessageRecord(smsId2)!!
|
|
||||||
val sms3: MessageRecord = smsDatabase.getMessageRecord(smsId3)!!
|
|
||||||
|
|
||||||
assertEquals(retrievedId, sms1.recipient.id)
|
|
||||||
assertEquals(retrievedId, sms2.recipient.id)
|
|
||||||
assertEquals(retrievedId, sms3.recipient.id)
|
|
||||||
|
|
||||||
assertEquals(retrievedThreadId, sms1.threadId)
|
|
||||||
assertEquals(retrievedThreadId, sms2.threadId)
|
|
||||||
assertEquals(retrievedThreadId, sms3.threadId)
|
|
||||||
|
|
||||||
// MMS validation
|
|
||||||
val mms1: MessageRecord = mmsDatabase.getMessageRecord(mmsId1)!!
|
|
||||||
val mms2: MessageRecord = mmsDatabase.getMessageRecord(mmsId2)!!
|
|
||||||
val mms3: MessageRecord = mmsDatabase.getMessageRecord(mmsId3)!!
|
|
||||||
|
|
||||||
assertEquals(retrievedId, mms1.recipient.id)
|
|
||||||
assertEquals(retrievedId, mms2.recipient.id)
|
|
||||||
assertEquals(retrievedId, mms3.recipient.id)
|
|
||||||
|
|
||||||
assertEquals(retrievedThreadId, mms1.threadId)
|
|
||||||
assertEquals(retrievedThreadId, mms2.threadId)
|
|
||||||
assertEquals(retrievedThreadId, mms3.threadId)
|
|
||||||
|
|
||||||
// Mention validation
|
|
||||||
val mention1: MentionModel = getMention(mmsId1)
|
|
||||||
assertEquals(retrievedId, mention1.recipientId)
|
|
||||||
assertEquals(retrievedThreadId, mention1.threadId)
|
|
||||||
|
|
||||||
val mention2: MentionModel = getMention(mmsId2)
|
|
||||||
assertEquals(retrievedId, mention2.recipientId)
|
|
||||||
assertEquals(retrievedThreadId, mention2.threadId)
|
|
||||||
|
|
||||||
// Group receipt validation
|
|
||||||
val groupReceipts: List<GroupReceiptDatabase.GroupReceiptInfo> = groupReceiptDatabase.getGroupReceiptInfo(mmsId1)
|
|
||||||
assertEquals(retrievedId, groupReceipts[0].recipientId)
|
|
||||||
assertEquals(retrievedId, groupReceipts[1].recipientId)
|
|
||||||
|
|
||||||
// Identity validation
|
|
||||||
assertEquals(identityKeyAci, identityDatabase.getIdentityStoreRecord(ACI_A.toString())!!.identityKey)
|
|
||||||
Assert.assertNull(identityDatabase.getIdentityStoreRecord(E164_A))
|
|
||||||
|
|
||||||
// Session validation
|
|
||||||
Assert.assertNotNull(sessionDatabase.load(localAci, SignalProtocolAddress(ACI_A.toString(), 1)))
|
|
||||||
|
|
||||||
// Reaction validation
|
|
||||||
val reactionsSms: List<ReactionRecord> = reactionDatabase.getReactions(MessageId(smsId1, false))
|
|
||||||
val reactionsMms: List<ReactionRecord> = reactionDatabase.getReactions(MessageId(mmsId1, true))
|
|
||||||
|
|
||||||
assertEquals(1, reactionsSms.size)
|
|
||||||
assertEquals(ReactionRecord("a", recipientIdAci, 1, 1), reactionsSms[0])
|
|
||||||
|
|
||||||
assertEquals(1, reactionsMms.size)
|
|
||||||
assertEquals(ReactionRecord("b", recipientIdAci, 1, 1), reactionsMms[0])
|
|
||||||
|
|
||||||
// Notification Profile validation
|
|
||||||
val updatedProfile1: NotificationProfile = notificationProfileDatabase.getProfile(profile1.id)!!
|
|
||||||
val updatedProfile2: NotificationProfile = notificationProfileDatabase.getProfile(profile2.id)!!
|
|
||||||
|
|
||||||
MatcherAssert.assertThat("Notification Profile 1 should now only contain ACI $recipientIdAci", updatedProfile1.allowedMembers, Matchers.containsInAnyOrder(recipientIdAci))
|
|
||||||
MatcherAssert.assertThat("Notification Profile 2 should now contain ACI A ($recipientIdAci) and ACI B ($recipientIdAciB)", updatedProfile2.allowedMembers, Matchers.containsInAnyOrder(recipientIdAci, recipientIdAciB))
|
|
||||||
|
|
||||||
// Distribution List validation
|
|
||||||
val updatedList: DistributionListRecord = distributionListDatabase.getList(distributionListId)!!
|
|
||||||
|
|
||||||
MatcherAssert.assertThat("Distribution list should have updated $recipientIdE164 to $recipientIdAci", updatedList.members, Matchers.containsInAnyOrder(recipientIdAci, recipientIdAciB))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============================================================
|
|
||||||
// Misc
|
|
||||||
// ==============================================================
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun createByE164SanityCheck() {
|
|
||||||
// GIVEN one recipient
|
|
||||||
val recipientId: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A)
|
|
||||||
|
|
||||||
// WHEN I retrieve one by E164
|
|
||||||
val possible: Optional<RecipientId> = recipientDatabase.getByE164(E164_A)
|
|
||||||
|
|
||||||
// THEN I get it back, and it has the properties I expect
|
|
||||||
assertTrue(possible.isPresent)
|
|
||||||
assertEquals(recipientId, possible.get())
|
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
|
||||||
assertTrue(recipient.e164.isPresent)
|
|
||||||
assertEquals(E164_A, recipient.e164.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun createByUuidSanityCheck() {
|
|
||||||
// GIVEN one recipient
|
|
||||||
val recipientId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
|
|
||||||
|
|
||||||
// WHEN I retrieve one by UUID
|
|
||||||
val possible: Optional<RecipientId> = recipientDatabase.getByServiceId(ACI_A)
|
|
||||||
|
|
||||||
// THEN I get it back, and it has the properties I expect
|
|
||||||
assertTrue(possible.isPresent)
|
|
||||||
assertEquals(recipientId, possible.get())
|
|
||||||
|
|
||||||
val recipient = Recipient.resolved(recipientId)
|
|
||||||
assertTrue(recipient.serviceId.isPresent)
|
|
||||||
assertEquals(ACI_A, recipient.serviceId.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class)
|
|
||||||
fun getAndPossiblyMerge_noArgs_invalid() {
|
|
||||||
recipientDatabase.getAndPossiblyMergeLegacy(null, null, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ensureDbEmpty() {
|
|
||||||
SignalDatabase.rawDatabase.rawQuery("SELECT COUNT(*) FROM ${RecipientDatabase.TABLE_NAME} WHERE ${RecipientDatabase.DISTRIBUTION_LIST_ID} IS NULL ", null).use { cursor ->
|
|
||||||
assertTrue(cursor.moveToFirst())
|
|
||||||
assertEquals(0, cursor.getLong(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun smsMessage(sender: RecipientId, time: Long = 0, body: String = "", groupId: Optional<GroupId> = Optional.empty()): IncomingTextMessage {
|
|
||||||
return IncomingTextMessage(sender, 1, time, time, time, body, groupId, 0, true, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun mmsMessage(sender: RecipientId, time: Long = 0, body: String = "", groupId: Optional<GroupId> = Optional.empty()): IncomingMediaMessage {
|
|
||||||
return IncomingMediaMessage(sender, groupId, body, time, time, time, emptyList(), 0, 0, false, false, true, Optional.empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun identityKey(value: Byte): IdentityKey {
|
|
||||||
val bytes = ByteArray(33)
|
|
||||||
bytes[0] = 0x05
|
|
||||||
bytes[1] = value
|
|
||||||
return IdentityKey(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun notificationProfile(name: String): NotificationProfile {
|
|
||||||
return (notificationProfileDatabase.createProfile(name = name, emoji = "", color = AvatarColor.A210, System.currentTimeMillis()) as NotificationProfileDatabase.NotificationProfileChangeResult.Success).notificationProfile
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun groupMasterKey(value: Byte): GroupMasterKey {
|
|
||||||
val bytes = ByteArray(32)
|
|
||||||
bytes[0] = value
|
|
||||||
return GroupMasterKey(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun decryptedGroup(members: Collection<UUID>): DecryptedGroup {
|
|
||||||
return DecryptedGroup.newBuilder()
|
|
||||||
.addAllMembers(members.map { DecryptedMember.newBuilder().setUuid(UuidUtil.toByteString(it)).build() })
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getMention(messageId: Long): MentionModel {
|
|
||||||
SignalDatabase.rawDatabase.rawQuery("SELECT * FROM ${MentionDatabase.TABLE_NAME} WHERE ${MentionDatabase.MESSAGE_ID} = $messageId").use { cursor ->
|
|
||||||
cursor.moveToFirst()
|
|
||||||
return MentionModel(
|
|
||||||
recipientId = RecipientId.from(CursorUtil.requireLong(cursor, MentionDatabase.RECIPIENT_ID)),
|
|
||||||
threadId = CursorUtil.requireLong(cursor, MentionDatabase.THREAD_ID)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The normal mention model doesn't have a threadId, so we need to do it ourselves for the test */
|
|
||||||
data class MentionModel(
|
|
||||||
val recipientId: RecipientId,
|
|
||||||
val threadId: Long
|
|
||||||
)
|
|
||||||
|
|
||||||
private class ChangeNumberListener {
|
|
||||||
|
|
||||||
var numberChangeWasEnqueued = false
|
|
||||||
private set
|
|
||||||
|
|
||||||
fun waitForJobManager() {
|
|
||||||
ApplicationDependencies.getJobManager().flush()
|
|
||||||
ThreadUtil.sleep(500)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enqueue() {
|
|
||||||
ApplicationDependencies.getJobManager().addListener(
|
|
||||||
{ job -> job.factoryKey == RecipientChangedNumberJob.KEY },
|
|
||||||
{ _, _ -> numberChangeWasEnqueued = true }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val ACI_A = ACI.from(UUID.fromString("3436efbe-5a76-47fa-a98a-7e72c948a82e"))
|
|
||||||
val ACI_B = ACI.from(UUID.fromString("8de7f691-0b60-4a68-9cd9-ed2f8453f9ed"))
|
|
||||||
|
|
||||||
val PNI_A = PNI.from(UUID.fromString("154b8d92-c960-4f6c-8385-671ad2ffb999"))
|
|
||||||
val PNI_B = PNI.from(UUID.fromString("ba92b1fb-cd55-40bf-adda-c35a85375533"))
|
|
||||||
|
|
||||||
const val E164_A = "+12221234567"
|
|
||||||
const val E164_B = "+13331234567"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -435,110 +435,8 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun getAndPossiblyMerge(serviceId: ServiceId?, e164: String?, changeSelf: Boolean = false): RecipientId {
|
fun getAndPossiblyMerge(serviceId: ServiceId?, e164: String?, changeSelf: Boolean = false): RecipientId {
|
||||||
return if (FeatureFlags.recipientMergeV2() || FeatureFlags.phoneNumberPrivacy()) {
|
|
||||||
getAndPossiblyMergePnp(serviceId, e164, changeSelf)
|
|
||||||
} else {
|
|
||||||
getAndPossiblyMergeLegacy(serviceId, e164, changeSelf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
fun getAndPossiblyMergeLegacy(serviceId: ServiceId?, e164: String?, changeSelf: Boolean = false): RecipientId {
|
|
||||||
require(!(serviceId == null && e164 == null)) { "Must provide an ACI or E164!" }
|
require(!(serviceId == null && e164 == null)) { "Must provide an ACI or E164!" }
|
||||||
|
return getAndPossiblyMerge(serviceId = serviceId, pni = null, e164 = e164, pniVerified = false, changeSelf = changeSelf)
|
||||||
val db = writableDatabase
|
|
||||||
|
|
||||||
var transactionSuccessful = false
|
|
||||||
var remapped: Pair<RecipientId, RecipientId>? = null
|
|
||||||
var recipientsNeedingRefresh: List<RecipientId> = listOf()
|
|
||||||
var recipientChangedNumber: RecipientId? = null
|
|
||||||
|
|
||||||
db.beginTransaction()
|
|
||||||
try {
|
|
||||||
val fetch: RecipientFetch = fetchRecipient(serviceId, e164, changeSelf = changeSelf)
|
|
||||||
|
|
||||||
if (fetch.logBundle != null) {
|
|
||||||
Log.w(TAG, fetch.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
val resolvedId: RecipientId = when (fetch) {
|
|
||||||
is RecipientFetch.Match -> {
|
|
||||||
fetch.id
|
|
||||||
}
|
|
||||||
is RecipientFetch.MatchAndUpdateE164 -> {
|
|
||||||
setPhoneNumberOrThrowSilent(fetch.id, fetch.e164)
|
|
||||||
recipientsNeedingRefresh = listOf(fetch.id)
|
|
||||||
recipientChangedNumber = fetch.changedNumber
|
|
||||||
fetch.id
|
|
||||||
}
|
|
||||||
is RecipientFetch.MatchAndReassignE164 -> {
|
|
||||||
removePhoneNumber(fetch.e164Id)
|
|
||||||
setPhoneNumberOrThrowSilent(fetch.id, fetch.e164)
|
|
||||||
recipientsNeedingRefresh = listOf(fetch.id, fetch.e164Id)
|
|
||||||
recipientChangedNumber = fetch.changedNumber
|
|
||||||
fetch.id
|
|
||||||
}
|
|
||||||
is RecipientFetch.MatchAndUpdateAci -> {
|
|
||||||
markRegistered(fetch.id, fetch.serviceId)
|
|
||||||
recipientsNeedingRefresh = listOf(fetch.id)
|
|
||||||
fetch.id
|
|
||||||
}
|
|
||||||
is RecipientFetch.MatchAndInsertAci -> {
|
|
||||||
val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(null, fetch.serviceId))
|
|
||||||
RecipientId.from(id)
|
|
||||||
}
|
|
||||||
is RecipientFetch.MatchAndMerge -> {
|
|
||||||
remapped = Pair(fetch.e164Id, fetch.sidId)
|
|
||||||
val mergedId: RecipientId = merge(fetch.sidId, fetch.e164Id)
|
|
||||||
recipientsNeedingRefresh = listOf(mergedId)
|
|
||||||
recipientChangedNumber = fetch.changedNumber
|
|
||||||
mergedId
|
|
||||||
}
|
|
||||||
is RecipientFetch.Insert -> {
|
|
||||||
val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(fetch.e164, fetch.serviceId))
|
|
||||||
RecipientId.from(id)
|
|
||||||
}
|
|
||||||
is RecipientFetch.InsertAndReassignE164 -> {
|
|
||||||
removePhoneNumber(fetch.e164Id)
|
|
||||||
recipientsNeedingRefresh = listOf(fetch.e164Id)
|
|
||||||
val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(fetch.e164, fetch.serviceId))
|
|
||||||
RecipientId.from(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transactionSuccessful = true
|
|
||||||
db.setTransactionSuccessful()
|
|
||||||
return resolvedId
|
|
||||||
} finally {
|
|
||||||
db.endTransaction()
|
|
||||||
|
|
||||||
if (transactionSuccessful) {
|
|
||||||
if (recipientsNeedingRefresh.isNotEmpty()) {
|
|
||||||
recipientsNeedingRefresh.forEach { ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(it) }
|
|
||||||
RetrieveProfileJob.enqueue(recipientsNeedingRefresh.toSet())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remapped != null) {
|
|
||||||
Recipient.live(remapped.first).refresh(remapped.second)
|
|
||||||
ApplicationDependencies.getRecipientCache().remap(remapped.first, remapped.second)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipientsNeedingRefresh.isNotEmpty() || remapped != null) {
|
|
||||||
StorageSyncHelper.scheduleSyncForDataChange()
|
|
||||||
RecipientId.clearCache()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipientChangedNumber != null) {
|
|
||||||
ApplicationDependencies.getJobManager().add(RecipientChangedNumberJob(recipientChangedNumber))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
fun getAndPossiblyMergePnp(serviceId: ServiceId?, e164: String?, changeSelf: Boolean = false): RecipientId {
|
|
||||||
require(!(serviceId == null && e164 == null)) { "Must provide an ACI or E164!" }
|
|
||||||
return getAndPossiblyMergePnp(serviceId = serviceId, pni = null, e164 = e164, pniVerified = false, changeSelf = changeSelf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -550,10 +448,10 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
throw AssertionError()
|
throw AssertionError()
|
||||||
}
|
}
|
||||||
|
|
||||||
return getAndPossiblyMergePnp(serviceId = serviceId, pni = pni, e164 = e164, pniVerified = true, changeSelf = false)
|
return getAndPossiblyMerge(serviceId = serviceId, pni = pni, e164 = e164, pniVerified = true, changeSelf = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAndPossiblyMergePnp(serviceId: ServiceId?, pni: PNI?, e164: String?, pniVerified: Boolean = false, changeSelf: Boolean = false): RecipientId {
|
private 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!" }
|
require(!(serviceId == null && e164 == null)) { "Must provide an ACI or E164!" }
|
||||||
|
|
||||||
if ((serviceId is PNI) && pni != null && serviceId != pni) {
|
if ((serviceId is PNI) && pni != null && serviceId != pni) {
|
||||||
|
@ -2135,7 +2033,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
* Associates the provided IDs together. The assumption here is that all of the IDs correspond to the local user and have been verified.
|
* 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) {
|
fun linkIdsForSelf(aci: ACI, pni: PNI, e164: String) {
|
||||||
getAndPossiblyMergePnp(serviceId = aci, pni = pni, e164 = e164, changeSelf = true, pniVerified = true)
|
getAndPossiblyMerge(serviceId = aci, pni = pni, e164 = e164, changeSelf = true, pniVerified = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2147,7 +2045,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
db.beginTransaction()
|
db.beginTransaction()
|
||||||
try {
|
try {
|
||||||
val id = Recipient.self().id
|
val id = Recipient.self().id
|
||||||
val newId = getAndPossiblyMergePnp(serviceId = SignalStore.account().requireAci(), pni = pni, e164 = e164, pniVerified = true, changeSelf = true)
|
val newId = getAndPossiblyMerge(serviceId = SignalStore.account().requireAci(), pni = pni, e164 = e164, pniVerified = true, changeSelf = true)
|
||||||
|
|
||||||
if (id == newId) {
|
if (id == newId) {
|
||||||
Log.i(TAG, "[updateSelfPhone] Phone updated for self")
|
Log.i(TAG, "[updateSelfPhone] Phone updated for self")
|
||||||
|
|
|
@ -114,6 +114,8 @@ public final class PushDecryptMessageJob extends BaseJob {
|
||||||
|
|
||||||
if (FeatureFlags.phoneNumberPrivacy() && result.getContent().getPniSignatureMessage().isPresent()) {
|
if (FeatureFlags.phoneNumberPrivacy() && result.getContent().getPniSignatureMessage().isPresent()) {
|
||||||
handlePniSignatureMessage(result.getContent().getSender(), result.getContent().getSenderDevice(), result.getContent().getPniSignatureMessage().get());
|
handlePniSignatureMessage(result.getContent().getSender(), result.getContent().getSenderDevice(), result.getContent().getPniSignatureMessage().get());
|
||||||
|
} else if (result.getContent().getPniSignatureMessage().isPresent()) {
|
||||||
|
Log.w(TAG, "Ignoring PNI signature because the feature flag is disabled!");
|
||||||
}
|
}
|
||||||
|
|
||||||
jobs.add(new PushProcessMessageJob(result.getContent(), smsMessageId, envelope.getTimestamp()));
|
jobs.add(new PushProcessMessageJob(result.getContent(), smsMessageId, envelope.getTimestamp()));
|
||||||
|
|
|
@ -537,13 +537,6 @@ public final class FeatureFlags {
|
||||||
return giftBadgeReceiveSupport() && getBoolean(GIFT_BADGE_SEND_SUPPORT, Environment.IS_STAGING);
|
return giftBadgeReceiveSupport() && getBoolean(GIFT_BADGE_SEND_SUPPORT, Environment.IS_STAGING);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not we should use the new recipient merging strategy.
|
|
||||||
*/
|
|
||||||
public static boolean recipientMergeV2() {
|
|
||||||
return getBoolean(RECIPIENT_MERGE_V2, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not we should enable the SMS exporter
|
* Whether or not we should enable the SMS exporter
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Reference in a new issue