Move from ACI to a generic ServiceId.

This commit is contained in:
Greyson Parrelli 2022-02-17 15:55:54 -05:00
parent 9f1deda220
commit 7ca2420287
110 changed files with 841 additions and 824 deletions

View file

@ -117,6 +117,48 @@ android {
} }
} }
testOptions {
execution 'ANDROIDX_TEST_ORCHESTRATOR'
unitTests {
includeAndroidResources = true
}
}
lintOptions {
checkReleaseBuilds false
abortOnError true
baseline file("lint-baseline.xml")
disable "LintError"
}
sourceSets {
test {
java.srcDirs += "$projectDir/src/testShared"
}
androidTest {
java.srcDirs += "$projectDir/src/testShared"
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JAVA_VERSION
targetCompatibility JAVA_VERSION
}
packagingOptions {
exclude 'LICENSE.txt'
exclude 'LICENSE'
exclude 'NOTICE'
exclude 'asm-license.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'META-INF/proguard/androidx-annotations.pro'
}
defaultConfig { defaultConfig {
versionCode canonicalVersionCode * postFixSize versionCode canonicalVersionCode * postFixSize
versionName canonicalVersionName versionName canonicalVersionName
@ -190,36 +232,6 @@ android {
testInstrumentationRunnerArguments clearPackageData: 'true' testInstrumentationRunnerArguments clearPackageData: 'true'
} }
testOptions {
execution 'ANDROIDX_TEST_ORCHESTRATOR'
}
sourceSets {
test {
java.srcDirs += "$projectDir/src/testShared"
}
androidTest {
java.srcDirs += "$projectDir/src/testShared"
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JAVA_VERSION
targetCompatibility JAVA_VERSION
}
packagingOptions {
exclude 'LICENSE.txt'
exclude 'LICENSE'
exclude 'NOTICE'
exclude 'asm-license.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'META-INF/proguard/androidx-annotations.pro'
}
buildTypes { buildTypes {
debug { debug {
if (keystores['debug'] != null) { if (keystores['debug'] != null) {
@ -371,19 +383,6 @@ android {
variant.setIgnore(true) variant.setIgnore(true)
} }
} }
lintOptions {
checkReleaseBuilds false
abortOnError true
baseline file("lint-baseline.xml")
disable "LintError"
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
} }
dependencies { dependencies {

View file

@ -4,7 +4,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -30,8 +29,8 @@ class RecipientDatabaseTest {
private lateinit var recipientDatabase: RecipientDatabase private lateinit var recipientDatabase: RecipientDatabase
private val localAci = ACI.from(UUID.randomUUID()); private val localAci = ACI.from(UUID.randomUUID())
private val localPni = PNI.from(UUID.randomUUID()); private val localPni = PNI.from(UUID.randomUUID())
@Before @Before
fun setup() { fun setup() {
@ -52,7 +51,7 @@ class RecipientDatabaseTest {
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, null, true) val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, null, true)
val recipient = Recipient.resolved(recipientId) val recipient = Recipient.resolved(recipientId)
assertEquals(ACI_A, recipient.requireAci()) assertEquals(ACI_A, recipient.requireServiceId())
assertFalse(recipient.hasE164()) assertFalse(recipient.hasE164())
} }
@ -62,7 +61,7 @@ class RecipientDatabaseTest {
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, null, false) val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, null, false)
val recipient = Recipient.resolved(recipientId) val recipient = Recipient.resolved(recipientId)
assertEquals(ACI_A, recipient.requireAci()) assertEquals(ACI_A, recipient.requireServiceId())
assertFalse(recipient.hasE164()) assertFalse(recipient.hasE164())
} }
@ -73,7 +72,7 @@ class RecipientDatabaseTest {
val recipient = Recipient.resolved(recipientId) val recipient = Recipient.resolved(recipientId)
assertEquals(E164_A, recipient.requireE164()) assertEquals(E164_A, recipient.requireE164())
assertFalse(recipient.hasAci()) assertFalse(recipient.hasServiceId())
} }
/** 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. */
@ -83,7 +82,7 @@ class RecipientDatabaseTest {
val recipient = Recipient.resolved(recipientId) val recipient = Recipient.resolved(recipientId)
assertEquals(E164_A, recipient.requireE164()) assertEquals(E164_A, recipient.requireE164())
assertFalse(recipient.hasAci()) assertFalse(recipient.hasServiceId())
} }
/** With high trust, you can associate an ACI-e164 pair. */ /** With high trust, you can associate an ACI-e164 pair. */
@ -92,7 +91,7 @@ class RecipientDatabaseTest {
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, true) val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, true)
val recipient = Recipient.resolved(recipientId) val recipient = Recipient.resolved(recipientId)
assertEquals(ACI_A, recipient.requireAci()) assertEquals(ACI_A, recipient.requireServiceId())
assertEquals(E164_A, recipient.requireE164()) assertEquals(E164_A, recipient.requireE164())
} }
@ -102,7 +101,7 @@ class RecipientDatabaseTest {
val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, false) val recipientId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, false)
val recipient = Recipient.resolved(recipientId) val recipient = Recipient.resolved(recipientId)
assertEquals(ACI_A, recipient.requireAci()) assertEquals(ACI_A, recipient.requireServiceId())
assertFalse(recipient.hasE164()) assertFalse(recipient.hasE164())
} }
@ -113,26 +112,26 @@ class RecipientDatabaseTest {
/** With high trust, you can associate an e164 with an existing ACI. */ /** With high trust, you can associate an e164 with an existing ACI. */
@Test @Test
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164_highTrust() { fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164_highTrust() {
val existingId: RecipientId = recipientDatabase.getOrInsertFromAci(ACI_A) val existingId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, true) val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, true)
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
} }
/** With low trust, you cannot associate an ACI-e164 pair, and therefore cannot store the e164. */ /** With low trust, you cannot associate an ACI-e164 pair, and therefore cannot store the e164. */
@Test @Test
fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164_lowTrust() { fun getAndPossiblyMerge_aciMapsToExistingUserButE164DoesNot_aciAndE164_lowTrust() {
val existingId: RecipientId = recipientDatabase.getOrInsertFromAci(ACI_A) val existingId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, false) val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, false)
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertFalse(retrievedRecipient.hasE164()) assertFalse(retrievedRecipient.hasE164())
} }
@ -145,7 +144,7 @@ class RecipientDatabaseTest {
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_B, retrievedRecipient.requireE164()) assertEquals(E164_B, retrievedRecipient.requireE164())
} }
@ -158,7 +157,7 @@ class RecipientDatabaseTest {
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
} }
@ -175,7 +174,7 @@ class RecipientDatabaseTest {
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
} }
@ -188,12 +187,12 @@ class RecipientDatabaseTest {
assertNotEquals(existingId, retrievedId) assertNotEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertFalse(retrievedRecipient.hasE164()) assertFalse(retrievedRecipient.hasE164())
val existingRecipient = Recipient.resolved(existingId) val existingRecipient = Recipient.resolved(existingId)
assertEquals(E164_A, existingRecipient.requireE164()) assertEquals(E164_A, existingRecipient.requireE164())
assertFalse(existingRecipient.hasAci()) assertFalse(existingRecipient.hasServiceId())
} }
/** We never change the ACI of an existing row. New ACI = new person, regardless of trust. But high trust lets us take the e164 from the current holder. */ /** We never change the ACI of an existing row. New ACI = new person, regardless of trust. But high trust lets us take the e164 from the current holder. */
@ -207,14 +206,12 @@ class RecipientDatabaseTest {
assertNotEquals(existingId, retrievedId) assertNotEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_B, retrievedRecipient.requireAci()) assertEquals(ACI_B, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
assertEquals(PNI_A, retrievedRecipient.pni.get())
val existingRecipient = Recipient.resolved(existingId) val existingRecipient = Recipient.resolved(existingId)
assertEquals(ACI_A, existingRecipient.requireAci()) assertEquals(ACI_A, existingRecipient.requireServiceId())
assertFalse(existingRecipient.hasE164()) assertFalse(existingRecipient.hasE164())
assertNull(existingRecipient.pni.orNull())
} }
/** We never change the ACI of an existing row. New ACI = new person, regardless of trust. And low trust means we cant take the e164. */ /** We never change the ACI of an existing row. New ACI = new person, regardless of trust. And low trust means we cant take the e164. */
@ -226,11 +223,11 @@ class RecipientDatabaseTest {
assertNotEquals(existingId, retrievedId) assertNotEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_B, retrievedRecipient.requireAci()) assertEquals(ACI_B, retrievedRecipient.requireServiceId())
assertFalse(retrievedRecipient.hasE164()) assertFalse(retrievedRecipient.hasE164())
val existingRecipient = Recipient.resolved(existingId) val existingRecipient = Recipient.resolved(existingId)
assertEquals(ACI_A, existingRecipient.requireAci()) assertEquals(ACI_A, existingRecipient.requireServiceId())
assertEquals(E164_A, existingRecipient.requireE164()) assertEquals(E164_A, existingRecipient.requireE164())
} }
@ -249,11 +246,11 @@ class RecipientDatabaseTest {
assertNotEquals(existingId, retrievedId) assertNotEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_B, retrievedRecipient.requireAci()) assertEquals(ACI_B, retrievedRecipient.requireServiceId())
assertFalse(retrievedRecipient.hasE164()) assertFalse(retrievedRecipient.hasE164())
val existingRecipient = Recipient.resolved(existingId) val existingRecipient = Recipient.resolved(existingId)
assertEquals(ACI_A, existingRecipient.requireAci()) assertEquals(ACI_A, existingRecipient.requireServiceId())
assertEquals(E164_A, existingRecipient.requireE164()) assertEquals(E164_A, existingRecipient.requireE164())
} }
@ -270,7 +267,7 @@ class RecipientDatabaseTest {
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
} }
@ -287,7 +284,7 @@ class RecipientDatabaseTest {
assertEquals(existingAciId, retrievedId) assertEquals(existingAciId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
val existingE164Recipient = Recipient.resolved(existingE164Id) val existingE164Recipient = Recipient.resolved(existingE164Id)
@ -310,7 +307,7 @@ class RecipientDatabaseTest {
assertEquals(existingAciId, retrievedId) assertEquals(existingAciId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
val existingE164Recipient = Recipient.resolved(existingE164Id) val existingE164Recipient = Recipient.resolved(existingE164Id)
@ -323,19 +320,19 @@ class RecipientDatabaseTest {
/** Low trust means you cant merge. If youre retrieving a user from the table with this data, prefer the ACI one. */ /** Low trust means you cant merge. If youre retrieving a user from the table with this data, prefer the ACI one. */
@Test @Test
fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_lowTrust() { fun getAndPossiblyMerge_bothAciAndE164MapToExistingUser_aciAndE164_lowTrust() {
val existingAciId: RecipientId = recipientDatabase.getOrInsertFromAci(ACI_A) val existingAciId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
val existingE164Id: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A) val existingE164Id: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A)
val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, false) val retrievedId: RecipientId = recipientDatabase.getAndPossiblyMerge(ACI_A, E164_A, false)
assertEquals(existingAciId, retrievedId) assertEquals(existingAciId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertFalse(retrievedRecipient.hasE164()) assertFalse(retrievedRecipient.hasE164())
val existingE164Recipient = Recipient.resolved(existingE164Id) val existingE164Recipient = Recipient.resolved(existingE164Id)
assertEquals(E164_A, existingE164Recipient.requireE164()) assertEquals(E164_A, existingE164Recipient.requireE164())
assertFalse(existingE164Recipient.hasAci()) assertFalse(existingE164Recipient.hasServiceId())
} }
/** Another high trust case. No new rules here, just a more complex scenario to show how different rules interact. */ /** Another high trust case. No new rules here, just a more complex scenario to show how different rules interact. */
@ -351,11 +348,11 @@ class RecipientDatabaseTest {
assertEquals(existingId1, retrievedId) assertEquals(existingId1, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
val existingRecipient2 = Recipient.resolved(existingId2) val existingRecipient2 = Recipient.resolved(existingId2)
assertEquals(ACI_B, existingRecipient2.requireAci()) assertEquals(ACI_B, existingRecipient2.requireServiceId())
assertFalse(existingRecipient2.hasE164()) assertFalse(existingRecipient2.hasE164())
assert(changeNumberListener.numberChangeWasEnqueued) assert(changeNumberListener.numberChangeWasEnqueued)
@ -371,11 +368,11 @@ class RecipientDatabaseTest {
assertEquals(existingId1, retrievedId) assertEquals(existingId1, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_B, retrievedRecipient.requireE164()) assertEquals(E164_B, retrievedRecipient.requireE164())
val existingRecipient2 = Recipient.resolved(existingId2) val existingRecipient2 = Recipient.resolved(existingId2)
assertEquals(ACI_B, existingRecipient2.requireAci()) assertEquals(ACI_B, existingRecipient2.requireServiceId())
assertEquals(E164_A, existingRecipient2.requireE164()) assertEquals(E164_A, existingRecipient2.requireE164())
} }
@ -392,7 +389,7 @@ class RecipientDatabaseTest {
assertEquals(existingId1, retrievedId) assertEquals(existingId1, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
assertFalse(recipientDatabase.getByE164(E164_B).isPresent) assertFalse(recipientDatabase.getByE164(E164_B).isPresent)
@ -417,11 +414,11 @@ class RecipientDatabaseTest {
assertEquals(existingId2, retrievedId) assertEquals(existingId2, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertFalse(retrievedRecipient.hasE164()) assertFalse(retrievedRecipient.hasE164())
val recipientWithId1 = Recipient.resolved(existingId1) val recipientWithId1 = Recipient.resolved(existingId1)
assertEquals(ACI_B, recipientWithId1.requireAci()) assertEquals(ACI_B, recipientWithId1.requireServiceId())
assertEquals(E164_A, recipientWithId1.requireE164()) assertEquals(E164_A, recipientWithId1.requireE164())
} }
@ -440,7 +437,7 @@ class RecipientDatabaseTest {
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
} }
@ -459,7 +456,7 @@ class RecipientDatabaseTest {
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_B, retrievedRecipient.requireE164()) assertEquals(E164_B, retrievedRecipient.requireE164())
} }
@ -475,7 +472,7 @@ class RecipientDatabaseTest {
assertEquals(existingId, retrievedId) assertEquals(existingId, retrievedId)
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_B, retrievedRecipient.requireE164()) assertEquals(E164_B, retrievedRecipient.requireE164())
changeNumberListener.waitForJobManager() changeNumberListener.waitForJobManager()
@ -506,18 +503,18 @@ class RecipientDatabaseTest {
@Test @Test
fun createByUuidSanityCheck() { fun createByUuidSanityCheck() {
// GIVEN one recipient // GIVEN one recipient
val recipientId: RecipientId = recipientDatabase.getOrInsertFromAci(ACI_A) val recipientId: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
// WHEN I retrieve one by UUID // WHEN I retrieve one by UUID
val possible: Optional<RecipientId> = recipientDatabase.getByAci(ACI_A) val possible: Optional<RecipientId> = recipientDatabase.getByServiceId(ACI_A)
// THEN I get it back, and it has the properties I expect // THEN I get it back, and it has the properties I expect
assertTrue(possible.isPresent) assertTrue(possible.isPresent)
assertEquals(recipientId, possible.get()) assertEquals(recipientId, possible.get())
val recipient = Recipient.resolved(recipientId) val recipient = Recipient.resolved(recipientId)
assertTrue(recipient.aci.isPresent) assertTrue(recipient.serviceId.isPresent)
assertEquals(ACI_A, recipient.aci.get()) assertEquals(ACI_A, recipient.serviceId.get())
} }
@Test(expected = IllegalArgumentException::class) @Test(expected = IllegalArgumentException::class)

View file

@ -53,8 +53,8 @@ class RecipientDatabaseTest_merges {
private lateinit var reactionDatabase: ReactionDatabase private lateinit var reactionDatabase: ReactionDatabase
private lateinit var notificationProfileDatabase: NotificationProfileDatabase private lateinit var notificationProfileDatabase: NotificationProfileDatabase
private val localAci = ACI.from(UUID.randomUUID()); private val localAci = ACI.from(UUID.randomUUID())
private val localPni = PNI.from(UUID.randomUUID()); private val localPni = PNI.from(UUID.randomUUID())
@Before @Before
fun setup() { fun setup() {
@ -80,9 +80,9 @@ class RecipientDatabaseTest_merges {
@Test @Test
fun getAndPossiblyMerge_general() { fun getAndPossiblyMerge_general() {
// Setup // Setup
val recipientIdAci: RecipientId = recipientDatabase.getOrInsertFromAci(ACI_A) val recipientIdAci: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_A)
val recipientIdE164: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A) val recipientIdE164: RecipientId = recipientDatabase.getOrInsertFromE164(E164_A)
val recipientIdAciB: RecipientId = recipientDatabase.getOrInsertFromAci(ACI_B) val recipientIdAciB: RecipientId = recipientDatabase.getOrInsertFromServiceId(ACI_B)
val smsId1: Long = smsDatabase.insertMessageInbox(smsMessage(sender = recipientIdAci, time = 0, body = "0")).get().messageId 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 smsId2: Long = smsDatabase.insertMessageInbox(smsMessage(sender = recipientIdE164, time = 1, body = "1")).get().messageId
@ -127,7 +127,7 @@ class RecipientDatabaseTest_merges {
// Recipient validation // Recipient validation
val retrievedRecipient = Recipient.resolved(retrievedId) val retrievedRecipient = Recipient.resolved(retrievedId)
assertEquals(ACI_A, retrievedRecipient.requireAci()) assertEquals(ACI_A, retrievedRecipient.requireServiceId())
assertEquals(E164_A, retrievedRecipient.requireE164()) assertEquals(E164_A, retrievedRecipient.requireE164())
val existingE164Recipient = Recipient.resolved(recipientIdE164) val existingE164Recipient = Recipient.resolved(recipientIdE164)

View file

@ -571,11 +571,11 @@ public final class ContactSelectionListFragment extends LoggingFragment
AlertDialog loadingDialog = SimpleProgressDialog.show(requireContext()); AlertDialog loadingDialog = SimpleProgressDialog.show(requireContext());
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> { SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
return UsernameUtil.fetchAciForUsername(requireContext(), contact.getNumber()); return UsernameUtil.fetchAciForUsername(contact.getNumber());
}, uuid -> { }, uuid -> {
loadingDialog.dismiss(); loadingDialog.dismiss();
if (uuid.isPresent()) { if (uuid.isPresent()) {
Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber()); Recipient recipient = Recipient.externalUsername(uuid.get(), contact.getNumber());
SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber()); SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber());
if (onContactSelectedListener != null) { if (onContactSelectedListener != null) {

View file

@ -75,7 +75,7 @@ public class NewConversationActivity extends ContactSelectionActivity
SimpleTask.run(getLifecycle(), () -> { SimpleTask.run(getLifecycle(), () -> {
Recipient resolved = Recipient.external(this, number); Recipient resolved = Recipient.external(this, number);
if (!resolved.isRegistered() || !resolved.hasAci()) { if (!resolved.isRegistered() || !resolved.hasServiceId()) {
Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh."); Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.");
try { try {
DirectoryHelper.refreshDirectoryFor(this, resolved, false); DirectoryHelper.refreshDirectoryFor(this, resolved, false);

View file

@ -26,8 +26,7 @@ import org.thoughtcrime.securesms.util.Hex
import org.thoughtcrime.securesms.util.SpanUtil import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.livedata.Store import org.thoughtcrime.securesms.util.livedata.Store
import org.whispersystems.signalservice.api.push.ACI import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.PNI
import java.util.Objects import java.util.Objects
/** /**
@ -61,18 +60,11 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
) )
if (!recipient.isGroup) { if (!recipient.isGroup) {
val aci = recipient.aci.transform(ACI::toString).or("null") val serviceId = recipient.serviceId.transform(ServiceId::toString).or("null")
longClickPref( longClickPref(
title = DSLSettingsText.from("ACI"), title = DSLSettingsText.from("ServiceId"),
summary = DSLSettingsText.from(aci), summary = DSLSettingsText.from(serviceId),
onLongClick = { copyToClipboard(aci) } onLongClick = { copyToClipboard(serviceId) }
)
val pni = recipient.pni.transform(PNI::toString).or("null")
longClickPref(
title = DSLSettingsText.from("PNI"),
summary = DSLSettingsText.from(pni),
onLongClick = { copyToClipboard(pni) }
) )
} }
@ -153,17 +145,8 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
.setTitle("Are you sure?") .setTitle("Are you sure?")
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() } .setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
.setPositiveButton(android.R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->
if (recipient.hasAci()) { if (recipient.hasServiceId()) {
SignalDatabase.sessions.deleteAllFor(accountId = Recipient.self().requireAci(), addressName = recipient.requireAci().toString()) SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireServiceId().toString())
SignalDatabase.sessions.deleteAllFor(accountId = Recipient.self().requirePni(), addressName = recipient.requireAci().toString())
}
if (recipient.hasE164()) {
SignalDatabase.sessions.deleteAllFor(accountId = Recipient.self().requireAci(), addressName = recipient.requireE164())
SignalDatabase.sessions.deleteAllFor(accountId = Recipient.self().requirePni(), addressName = recipient.requireE164())
}
if (recipient.hasPni()) {
SignalDatabase.sessions.deleteAllFor(accountId = Recipient.self().requireAci(), addressName = recipient.requirePni().toString())
SignalDatabase.sessions.deleteAllFor(accountId = Recipient.self().requirePni(), addressName = recipient.requirePni().toString())
} }
} }
.show() .show()

View file

@ -127,10 +127,10 @@ data class CallParticipantsState(
fun getIncomingRingingGroupDescription(context: Context): String? { fun getIncomingRingingGroupDescription(context: Context): String? {
if (callState == WebRtcViewModel.State.CALL_INCOMING && if (callState == WebRtcViewModel.State.CALL_INCOMING &&
groupCallState == WebRtcViewModel.GroupCallState.RINGING && groupCallState == WebRtcViewModel.GroupCallState.RINGING &&
ringerRecipient.hasAci() ringerRecipient.hasServiceId()
) { ) {
val ringerName = ringerRecipient.getShortDisplayName(context) val ringerName = ringerRecipient.getShortDisplayName(context)
val membersWithoutYouOrRinger: List<GroupMemberEntry.FullMember> = groupMembers.filterNot { it.member.isSelf || ringerRecipient.requireAci() == it.member.aci.orNull() } val membersWithoutYouOrRinger: List<GroupMemberEntry.FullMember> = groupMembers.filterNot { it.member.isSelf || ringerRecipient.requireServiceId() == it.member.serviceId.orNull() }
return when (membersWithoutYouOrRinger.size) { return when (membersWithoutYouOrRinger.size) {
0 -> context.getString(R.string.WebRtcCallView__s_is_calling_you, ringerName) 0 -> context.getString(R.string.WebRtcCallView__s_is_calling_you, ringerName)

View file

@ -112,9 +112,9 @@ public class DirectoryHelper {
RecipientDatabase recipientDatabase = SignalDatabase.recipients(); RecipientDatabase recipientDatabase = SignalDatabase.recipients();
for (Recipient recipient : recipients) { for (Recipient recipient : recipients) {
if (recipient.hasAci() && !recipient.hasE164()) { if (recipient.hasServiceId() && !recipient.hasE164()) {
if (ApplicationDependencies.getSignalServiceAccountManager().isIdentifierRegistered(recipient.requireAci())) { if (ApplicationDependencies.getSignalServiceAccountManager().isIdentifierRegistered(recipient.requireServiceId())) {
recipientDatabase.markRegistered(recipient.getId(), recipient.requireAci()); recipientDatabase.markRegistered(recipient.getId(), recipient.requireServiceId());
} else { } else {
recipientDatabase.markUnregistered(recipient.getId()); recipientDatabase.markUnregistered(recipient.getId());
} }
@ -136,11 +136,11 @@ public class DirectoryHelper {
RegisteredState originalRegisteredState = recipient.resolve().getRegistered(); RegisteredState originalRegisteredState = recipient.resolve().getRegistered();
RegisteredState newRegisteredState; RegisteredState newRegisteredState;
if (recipient.hasAci() && !recipient.hasE164()) { if (recipient.hasServiceId() && !recipient.hasE164()) {
boolean isRegistered = ApplicationDependencies.getSignalServiceAccountManager().isIdentifierRegistered(recipient.requireAci()); boolean isRegistered = ApplicationDependencies.getSignalServiceAccountManager().isIdentifierRegistered(recipient.requireServiceId());
stopwatch.split("aci-network"); stopwatch.split("aci-network");
if (isRegistered) { if (isRegistered) {
boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), recipient.requireAci()); boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), recipient.requireServiceId());
if (idChanged) { if (idChanged) {
Log.w(TAG, "ID changed during refresh by UUID."); Log.w(TAG, "ID changed during refresh by UUID.");
} }
@ -173,14 +173,14 @@ public class DirectoryHelper {
if (aci != null) { if (aci != null) {
boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), aci); boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), aci);
if (idChanged) { if (idChanged) {
recipient = Recipient.resolved(recipientDatabase.getByAci(aci).get()); recipient = Recipient.resolved(recipientDatabase.getByServiceId(aci).get());
} }
} else { } else {
Log.w(TAG, "Registered number set had a null ACI!"); Log.w(TAG, "Registered number set had a null ACI!");
} }
} else if (recipient.hasAci() && recipient.isRegistered() && hasCommunicatedWith(recipient)) { } else if (recipient.hasServiceId() && recipient.isRegistered() && hasCommunicatedWith(recipient)) {
if (ApplicationDependencies.getSignalServiceAccountManager().isIdentifierRegistered(recipient.requireAci())) { if (ApplicationDependencies.getSignalServiceAccountManager().isIdentifierRegistered(recipient.requireServiceId())) {
recipientDatabase.markRegistered(recipient.getId(), recipient.requireAci()); recipientDatabase.markRegistered(recipient.getId(), recipient.requireServiceId());
} else { } else {
recipientDatabase.markUnregistered(recipient.getId()); recipientDatabase.markUnregistered(recipient.getId());
} }
@ -485,7 +485,13 @@ public class DirectoryHelper {
} }
public static boolean hasSession(@NonNull RecipientId id) { public static boolean hasSession(@NonNull RecipientId id) {
SignalProtocolAddress protocolAddress = new SignalProtocolAddress(Recipient.resolved(id).requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID); Recipient recipient = Recipient.resolved(id);
if (!recipient.hasServiceId()) {
return false;
}
SignalProtocolAddress protocolAddress = Recipient.resolved(id).requireServiceId().toProtocolAddress(SignalServiceAddress.DEFAULT_DEVICE_ID);
return ApplicationDependencies.getProtocolStore().aci().containsSession(protocolAddress) || return ApplicationDependencies.getProtocolStore().aci().containsSession(protocolAddress) ||
ApplicationDependencies.getProtocolStore().pni().containsSession(protocolAddress); ApplicationDependencies.getProtocolStore().pni().containsSession(protocolAddress);
@ -511,7 +517,7 @@ public class DirectoryHelper {
List<Recipient> possiblyUnlisted = Stream.of(inactiveIds) List<Recipient> possiblyUnlisted = Stream.of(inactiveIds)
.map(Recipient::resolved) .map(Recipient::resolved)
.filter(Recipient::isRegistered) .filter(Recipient::isRegistered)
.filter(Recipient::hasAci) .filter(Recipient::hasServiceId)
.filter(DirectoryHelper::hasCommunicatedWith) .filter(DirectoryHelper::hasCommunicatedWith)
.toList(); .toList();
@ -546,12 +552,9 @@ public class DirectoryHelper {
} }
private static boolean hasCommunicatedWith(@NonNull Recipient recipient) { private static boolean hasCommunicatedWith(@NonNull Recipient recipient) {
ACI localAci = Recipient.self().requireAci(); ACI localAci = SignalStore.account().requireAci();
return SignalDatabase.threads().hasThread(recipient.getId()) || return SignalDatabase.threads().hasThread(recipient.getId()) || (recipient.hasServiceId() && SignalDatabase.sessions().hasSessionFor(localAci, recipient.requireServiceId().toString()));
(recipient.hasAci() && SignalDatabase.sessions().hasSessionFor(localAci, recipient.requireAci().toString())) ||
(recipient.hasPni() && SignalDatabase.sessions().hasSessionFor(localAci, recipient.requirePni().toString())) ||
(recipient.hasE164() && SignalDatabase.sessions().hasSessionFor(localAci, recipient.requireE164()));
} }
static class DirectoryResult { static class DirectoryResult {

View file

@ -1554,14 +1554,14 @@ public class ConversationParentFragment extends Fragment
smsEnabled = false; smsEnabled = false;
} }
if (!isSecureText && !isPushGroupConversation() && !recipient.get().isAciOnly() && !recipient.get().isReleaseNotes() && smsEnabled) { if (!isSecureText && !isPushGroupConversation() && !recipient.get().isServiceIdOnly() && !recipient.get().isReleaseNotes() && smsEnabled) {
sendButton.disableTransport(Type.TEXTSECURE); sendButton.disableTransport(Type.TEXTSECURE);
} }
if (!recipient.get().isPushGroup() && recipient.get().isForceSmsSelection() && smsEnabled) { if (!recipient.get().isPushGroup() && recipient.get().isForceSmsSelection() && smsEnabled) {
sendButton.setDefaultTransport(Type.SMS); sendButton.setDefaultTransport(Type.SMS);
} else { } else {
if (isSecureText || isPushGroupConversation() || recipient.get().isAciOnly() || recipient.get().isReleaseNotes() || !smsEnabled) { if (isSecureText || isPushGroupConversation() || recipient.get().isServiceIdOnly() || recipient.get().isReleaseNotes() || !smsEnabled) {
sendButton.setDefaultTransport(Type.TEXTSECURE); sendButton.setDefaultTransport(Type.TEXTSECURE);
} else { } else {
sendButton.setDefaultTransport(Type.SMS); sendButton.setDefaultTransport(Type.SMS);
@ -3013,7 +3013,7 @@ public class ConversationParentFragment extends Fragment
return new SettableFuture<>(null); return new SettableFuture<>(null);
} }
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isAciOnly(); final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isServiceIdOnly();
final long thread = this.threadId; final long thread = this.threadId;
if (sendPush) { if (sendPush) {
@ -3076,7 +3076,7 @@ public class ConversationParentFragment extends Fragment
final long thread = this.threadId; final long thread = this.threadId;
final Context context = requireContext().getApplicationContext(); final Context context = requireContext().getApplicationContext();
final String messageBody = getMessage(); final String messageBody = getMessage();
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isAciOnly(); final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isServiceIdOnly();
OutgoingTextMessage message; OutgoingTextMessage message;

View file

@ -7,7 +7,6 @@ import android.text.SpannableString;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
@ -52,6 +51,7 @@ import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
@ -351,12 +351,12 @@ public final class ConversationUpdateItem extends FrameLayout
} }
}); });
} else if (conversationMessage.getMessageRecord().isGroupCall()) { } else if (conversationMessage.getMessageRecord().isGroupCall()) {
UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true); UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true);
Collection<ACI> acis = updateDescription.getMentioned(); Collection<ServiceId> acis = updateDescription.getMentioned();
int text = 0; int text = 0;
if (Util.hasItems(acis)) { if (Util.hasItems(acis)) {
if (acis.contains(Recipient.self().requireAci())) { if (acis.contains(Recipient.self().requireServiceId())) {
text = R.string.ConversationUpdateItem_return_to_call; text = R.string.ConversationUpdateItem_return_to_call;
} else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).getIsCallFull()) { } else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).getIsCallFull()) {
text = R.string.ConversationUpdateItem_call_is_full; text = R.string.ConversationUpdateItem_call_is_full;

View file

@ -126,7 +126,7 @@ final class SafetyNumberChangeRepository {
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
for (ChangedRecipient changedRecipient : changedRecipients) { for (ChangedRecipient changedRecipient : changedRecipients) {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(changedRecipient.getRecipient().requireServiceId(), SignalServiceAddress.DEFAULT_DEVICE_ID); SignalProtocolAddress mismatchAddress = changedRecipient.getRecipient().requireServiceId().toProtocolAddress(SignalServiceAddress.DEFAULT_DEVICE_ID);
Log.d(TAG, "Saving identity for: " + changedRecipient.getRecipient().getId() + " " + changedRecipient.getIdentityRecord().getIdentityKey().hashCode()); Log.d(TAG, "Saving identity for: " + changedRecipient.getRecipient().getId() + " " + changedRecipient.getIdentityRecord().getIdentityKey().hashCode());
SignalIdentityKeyStore.SaveResult result = ApplicationDependencies.getProtocolStore().aci().identities().saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true); SignalIdentityKeyStore.SaveResult result = ApplicationDependencies.getProtocolStore().aci().identities().saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true);

View file

@ -22,7 +22,7 @@ public final class SenderKeyUtil {
*/ */
public static void rotateOurKey(@NonNull Context context, @NonNull DistributionId distributionId) { public static void rotateOurKey(@NonNull Context context, @NonNull DistributionId distributionId) {
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
ApplicationDependencies.getProtocolStore().aci().senderKeys().deleteAllFor(Recipient.self().requireServiceId(), distributionId); ApplicationDependencies.getProtocolStore().aci().senderKeys().deleteAllFor(SignalStore.account().requireAci().toString(), distributionId);
SignalDatabase.senderKeyShared().deleteAllFor(distributionId); SignalDatabase.senderKeyShared().deleteAllFor(distributionId);
} }
} }
@ -31,7 +31,7 @@ public final class SenderKeyUtil {
* Gets when the sender key session was created, or -1 if it doesn't exist. * Gets when the sender key session was created, or -1 if it doesn't exist.
*/ */
public static long getCreateTimeForOurKey(@NonNull Context context, @NonNull DistributionId distributionId) { public static long getCreateTimeForOurKey(@NonNull Context context, @NonNull DistributionId distributionId) {
SignalProtocolAddress address = new SignalProtocolAddress(Recipient.self().requireServiceId(), SignalStore.account().getDeviceId()); SignalProtocolAddress address = new SignalProtocolAddress(SignalStore.account().requireAci().toString(), SignalStore.account().getDeviceId());
return SignalDatabase.senderKeys().getCreatedTime(address, distributionId); return SignalDatabase.senderKeys().getCreatedTime(address, distributionId);
} }

View file

@ -23,6 +23,7 @@ import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.SignalProtocolAddress; import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.state.IdentityKeyStore; import org.whispersystems.libsignal.state.IdentityKeyStore;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -110,8 +111,8 @@ public class SignalBaseIdentityKeyStore {
boolean nonBlockingApproval) boolean nonBlockingApproval)
{ {
Recipient recipient = Recipient.resolved(recipientId); Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasServiceIdentifier()) { if (recipient.hasServiceId()) {
cache.save(recipient.requireServiceId(), recipientId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval); cache.save(recipient.requireServiceId().toString(), recipientId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval);
} else { } else {
Log.w(TAG, "[saveIdentity] No serviceId for " + recipient.getId()); Log.w(TAG, "[saveIdentity] No serviceId for " + recipient.getId());
} }
@ -120,7 +121,7 @@ public class SignalBaseIdentityKeyStore {
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, IdentityKeyStore.Direction direction) { public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, IdentityKeyStore.Direction direction) {
Recipient self = Recipient.self(); Recipient self = Recipient.self();
boolean isSelf = address.getName().equals(self.requireAci().toString()) || boolean isSelf = address.getName().equals(self.requireServiceId().toString()) ||
address.getName().equals(self.requireE164()); address.getName().equals(self.requireE164());
if (isSelf) { if (isSelf) {
@ -150,19 +151,20 @@ public class SignalBaseIdentityKeyStore {
} }
public @NonNull Optional<IdentityRecord> getIdentityRecord(@NonNull Recipient recipient) { public @NonNull Optional<IdentityRecord> getIdentityRecord(@NonNull Recipient recipient) {
if (recipient.hasServiceIdentifier()) { if (recipient.hasServiceId()) {
IdentityStoreRecord record = cache.get(recipient.requireServiceId()); IdentityStoreRecord record = cache.get(recipient.requireServiceId().toString());
return Optional.fromNullable(record).transform(r -> r.toIdentityRecord(recipient.getId())); return Optional.fromNullable(record).transform(r -> r.toIdentityRecord(recipient.getId()));
} else { } else {
Log.w(TAG, "[getIdentityRecord] No serviceId for " + recipient.getId()); Log.w(TAG, "[getIdentityRecord] No ServiceId for " + recipient.getId());
return Optional.absent(); return Optional.absent();
} }
} }
public @NonNull IdentityRecordList getIdentityRecords(@NonNull List<Recipient> recipients) { public @NonNull IdentityRecordList getIdentityRecords(@NonNull List<Recipient> recipients) {
List<String> addressNames = recipients.stream() List<String> addressNames = recipients.stream()
.filter(Recipient::hasServiceIdentifier) .filter(Recipient::hasServiceId)
.map(Recipient::requireServiceId) .map(Recipient::requireServiceId)
.map(ServiceId::toString)
.collect(Collectors.toList()); .collect(Collectors.toList());
if (addressNames.isEmpty()) { if (addressNames.isEmpty()) {
@ -172,8 +174,8 @@ public class SignalBaseIdentityKeyStore {
List<IdentityRecord> records = new ArrayList<>(recipients.size()); List<IdentityRecord> records = new ArrayList<>(recipients.size());
for (Recipient recipient : recipients) { for (Recipient recipient : recipients) {
if (recipient.hasServiceIdentifier()) { if (recipient.hasServiceId()) {
IdentityStoreRecord record = cache.get(recipient.requireServiceId()); IdentityStoreRecord record = cache.get(recipient.requireServiceId().toString());
if (record != null) { if (record != null) {
records.add(record.toIdentityRecord(recipient.getId())); records.add(record.toIdentityRecord(recipient.getId()));
@ -189,8 +191,8 @@ public class SignalBaseIdentityKeyStore {
public void setApproval(@NonNull RecipientId recipientId, boolean nonBlockingApproval) { public void setApproval(@NonNull RecipientId recipientId, boolean nonBlockingApproval) {
Recipient recipient = Recipient.resolved(recipientId); Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasServiceIdentifier()) { if (recipient.hasServiceId()) {
cache.setApproval(recipient.requireServiceId(), recipientId, nonBlockingApproval); cache.setApproval(recipient.requireServiceId().toString(), recipientId, nonBlockingApproval);
} else { } else {
Log.w(TAG, "[setApproval] No serviceId for " + recipient.getId()); Log.w(TAG, "[setApproval] No serviceId for " + recipient.getId());
} }
@ -199,8 +201,8 @@ public class SignalBaseIdentityKeyStore {
public void setVerified(@NonNull RecipientId recipientId, IdentityKey identityKey, VerifiedStatus verifiedStatus) { public void setVerified(@NonNull RecipientId recipientId, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
Recipient recipient = Recipient.resolved(recipientId); Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasServiceIdentifier()) { if (recipient.hasServiceId()) {
cache.setVerified(recipient.requireServiceId(), recipientId, identityKey, verifiedStatus); cache.setVerified(recipient.requireServiceId().toString(), recipientId, identityKey, verifiedStatus);
} else { } else {
Log.w(TAG, "[setVerified] No serviceId for " + recipient.getId()); Log.w(TAG, "[setVerified] No serviceId for " + recipient.getId());
} }

View file

@ -7,7 +7,7 @@ import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceDataStore; import org.whispersystems.signalservice.api.SignalServiceDataStore;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
public final class SignalServiceDataStoreImpl implements SignalServiceDataStore { public final class SignalServiceDataStoreImpl implements SignalServiceDataStore {
@ -25,7 +25,7 @@ public final class SignalServiceDataStoreImpl implements SignalServiceDataStore
} }
@Override @Override
public SignalServiceAccountDataStoreImpl get(@NonNull AccountIdentifier accountIdentifier) { public SignalServiceAccountDataStoreImpl get(@NonNull ServiceId accountIdentifier) {
if (accountIdentifier.equals(SignalStore.account().getAci())) { if (accountIdentifier.equals(SignalStore.account().getAci())) {
return aciStore; return aciStore;
} else if (accountIdentifier.equals(SignalStore.account().getPni())) { } else if (accountIdentifier.equals(SignalStore.account().getPni())) {

View file

@ -9,7 +9,7 @@ import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.PreKeyStore; import org.whispersystems.libsignal.state.PreKeyStore;
import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyStore; import org.whispersystems.libsignal.state.SignedPreKeyStore;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.List; import java.util.List;
@ -21,9 +21,9 @@ public class TextSecurePreKeyStore implements PreKeyStore, SignedPreKeyStore {
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
@NonNull @NonNull
private final AccountIdentifier accountId; private final ServiceId accountId;
public TextSecurePreKeyStore(@NonNull AccountIdentifier accountId) { public TextSecurePreKeyStore(@NonNull ServiceId accountId) {
this.accountId = accountId; this.accountId = accountId;
} }

View file

@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.crypto.storage; package org.thoughtcrime.securesms.crypto.storage;
import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -15,7 +13,7 @@ import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.protocol.CiphertextMessage; import org.whispersystems.libsignal.protocol.CiphertextMessage;
import org.whispersystems.libsignal.state.SessionRecord; import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.signalservice.api.SignalServiceSessionStore; import org.whispersystems.signalservice.api.SignalServiceSessionStore;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -28,9 +26,9 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
private final AccountIdentifier accountId; private final ServiceId accountId;
public TextSecureSessionStore(@NonNull AccountIdentifier accountId) { public TextSecureSessionStore(@NonNull ServiceId accountId) {
this.accountId = accountId; this.accountId = accountId;
} }
@ -135,8 +133,8 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
synchronized (LOCK) { synchronized (LOCK) {
Recipient recipient = Recipient.resolved(recipientId); Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasAci()) { if (recipient.hasServiceId()) {
archiveSession(new SignalProtocolAddress(recipient.requireAci().toString(), deviceId)); archiveSession(new SignalProtocolAddress(recipient.requireServiceId().toString(), deviceId));
} }
if (recipient.hasE164()) { if (recipient.hasE164()) {

View file

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.crypto.SenderKeyUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor; import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor;
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob; import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.DistributionId;
import org.thoughtcrime.securesms.groups.GroupAccessControl; import org.thoughtcrime.securesms.groups.GroupAccessControl;
@ -40,6 +41,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.groupsv2.GroupChangeReconstruct; import org.whispersystems.signalservice.api.groupsv2.GroupChangeReconstruct;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.Closeable; import java.io.Closeable;
@ -821,7 +823,7 @@ private static final String[] GROUP_PROJECTION = {
} }
private static boolean gv2GroupActive(@NonNull DecryptedGroup decryptedGroup) { private static boolean gv2GroupActive(@NonNull DecryptedGroup decryptedGroup) {
ACI aci = Recipient.self().requireAci(); ACI aci = SignalStore.account().requireAci();
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), aci.uuid()).isPresent() || return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), aci.uuid()).isPresent() ||
DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), aci.uuid()).isPresent(); DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), aci.uuid()).isPresent();
@ -1232,9 +1234,9 @@ private static final String[] GROUP_PROJECTION = {
*/ */
public boolean isPendingMember(@NonNull Recipient recipient) { public boolean isPendingMember(@NonNull Recipient recipient) {
if (isV2Group()) { if (isV2Group()) {
Optional<ACI> aci = recipient.getAci(); Optional<ServiceId> serviceId = recipient.getServiceId();
if (aci.isPresent()) { if (serviceId.isPresent()) {
return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().getDecryptedGroup().getPendingMembersList(), aci.get().uuid()) return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().getDecryptedGroup().getPendingMembersList(), serviceId.get().uuid())
.isPresent(); .isPresent();
} }
} }
@ -1275,13 +1277,13 @@ private static final String[] GROUP_PROJECTION = {
} }
public boolean isAdmin(@NonNull Recipient recipient) { public boolean isAdmin(@NonNull Recipient recipient) {
Optional<ACI> aci = recipient.getAci(); Optional<ServiceId> serviceId = recipient.getServiceId();
if (!aci.isPresent()) { if (!serviceId.isPresent()) {
return false; return false;
} }
return DecryptedGroupUtil.findMemberByUuid(getDecryptedGroup().getMembersList(), aci.get().uuid()) return DecryptedGroupUtil.findMemberByUuid(getDecryptedGroup().getMembersList(), serviceId.get().uuid())
.transform(t -> t.getRole() == Member.Role.ADMINISTRATOR) .transform(t -> t.getRole() == Member.Role.ADMINISTRATOR)
.or(false); .or(false);
} }
@ -1291,21 +1293,21 @@ private static final String[] GROUP_PROJECTION = {
} }
public MemberLevel memberLevel(@NonNull Recipient recipient) { public MemberLevel memberLevel(@NonNull Recipient recipient) {
Optional<ACI> aci = recipient.getAci(); Optional<ServiceId> serviceId = recipient.getServiceId();
if (!aci.isPresent()) { if (!serviceId.isPresent()) {
return MemberLevel.NOT_A_MEMBER; return MemberLevel.NOT_A_MEMBER;
} }
DecryptedGroup decryptedGroup = getDecryptedGroup(); DecryptedGroup decryptedGroup = getDecryptedGroup();
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), aci.get().uuid()) return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), serviceId.get().uuid())
.transform(member -> member.getRole() == Member.Role.ADMINISTRATOR .transform(member -> member.getRole() == Member.Role.ADMINISTRATOR
? MemberLevel.ADMINISTRATOR ? MemberLevel.ADMINISTRATOR
: MemberLevel.FULL_MEMBER) : MemberLevel.FULL_MEMBER)
.or(() -> DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), aci.get().uuid()) .or(() -> DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), serviceId.get().uuid())
.transform(m -> MemberLevel.PENDING_MEMBER) .transform(m -> MemberLevel.PENDING_MEMBER)
.or(() -> DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.getRequestingMembersList(), aci.get().uuid()) .or(() -> DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.getRequestingMembersList(), serviceId.get().uuid())
.transform(m -> MemberLevel.REQUESTING_MEMBER) .transform(m -> MemberLevel.REQUESTING_MEMBER)
.or(MemberLevel.NOT_A_MEMBER))); .or(MemberLevel.NOT_A_MEMBER)));
} }
@ -1317,7 +1319,7 @@ private static final String[] GROUP_PROJECTION = {
public List<RecipientId> getMemberRecipientIds(@NonNull MemberSet memberSet) { public List<RecipientId> getMemberRecipientIds(@NonNull MemberSet memberSet) {
boolean includeSelf = memberSet.includeSelf; boolean includeSelf = memberSet.includeSelf;
DecryptedGroup groupV2 = getDecryptedGroup(); DecryptedGroup groupV2 = getDecryptedGroup();
UUID selfUuid = Recipient.self().requireAci().uuid(); UUID selfUuid = Recipient.self().requireServiceId().uuid();
List<RecipientId> recipients = new ArrayList<>(groupV2.getMembersCount() + groupV2.getPendingMembersCount()); List<RecipientId> recipients = new ArrayList<>(groupV2.getMembersCount() + groupV2.getPendingMembersCount());
int unknownMembers = 0; int unknownMembers = 0;
int unknownPending = 0; int unknownPending = 0;

View file

@ -19,7 +19,6 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -106,7 +105,7 @@ public final class MentionUtil {
BodyRangeList.Builder builder = BodyRangeList.newBuilder(); BodyRangeList.Builder builder = BodyRangeList.newBuilder();
for (Mention mention : mentions) { for (Mention mention : mentions) {
String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString(); String uuid = Recipient.resolved(mention.getRecipientId()).requireServiceId().toString();
builder.addRanges(BodyRangeList.BodyRange.newBuilder() builder.addRanges(BodyRangeList.BodyRange.newBuilder()
.setMentionUuid(uuid) .setMentionUuid(uuid)
.setStart(mention.getStart()) .setStart(mention.getStart())
@ -122,7 +121,7 @@ public final class MentionUtil {
return Stream.of(BodyRangeList.parseFrom(data).getRangesList()) return Stream.of(BodyRangeList.parseFrom(data).getRangesList())
.filter(bodyRange -> bodyRange.getAssociatedValueCase() == BodyRangeList.BodyRange.AssociatedValueCase.MENTIONUUID) .filter(bodyRange -> bodyRange.getAssociatedValueCase() == BodyRangeList.BodyRange.AssociatedValueCase.MENTIONUUID)
.map(mention -> { .map(mention -> {
RecipientId id = Recipient.externalPush(context, ACI.parseOrThrow(mention.getMentionUuid()), null, false).getId(); RecipientId id = Recipient.externalPush(ACI.parseOrThrow(mention.getMentionUuid()), null, false).getId();
return new Mention(id, mention.getStart(), mention.getLength()); return new Mention(id, mention.getStart(), mention.getLength());
}) })
.toList(); .toList();

View file

@ -9,7 +9,7 @@ import org.whispersystems.libsignal.InvalidKeyException
import org.whispersystems.libsignal.ecc.Curve import org.whispersystems.libsignal.ecc.Curve
import org.whispersystems.libsignal.ecc.ECKeyPair import org.whispersystems.libsignal.ecc.ECKeyPair
import org.whispersystems.libsignal.state.PreKeyRecord import org.whispersystems.libsignal.state.PreKeyRecord
import org.whispersystems.signalservice.api.push.AccountIdentifier import org.whispersystems.signalservice.api.push.ServiceId
import java.io.IOException import java.io.IOException
class OneTimePreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) { class OneTimePreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) {
@ -34,8 +34,8 @@ class OneTimePreKeyDatabase(context: Context, databaseHelper: SignalDatabase) :
""" """
} }
fun get(accountId: AccountIdentifier, keyId: Int): PreKeyRecord? { fun get(serviceId: ServiceId, keyId: Int): PreKeyRecord? {
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(accountId, keyId), null, null, null).use { cursor -> readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId), null, null, null).use { cursor ->
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
try { try {
val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0) val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0)
@ -52,9 +52,9 @@ class OneTimePreKeyDatabase(context: Context, databaseHelper: SignalDatabase) :
return null return null
} }
fun insert(accountId: AccountIdentifier, keyId: Int, record: PreKeyRecord) { fun insert(serviceId: ServiceId, keyId: Int, record: PreKeyRecord) {
val contentValues = contentValuesOf( val contentValues = contentValuesOf(
ACCOUNT_ID to accountId.toString(), ACCOUNT_ID to serviceId.toString(),
KEY_ID to keyId, KEY_ID to keyId,
PUBLIC_KEY to Base64.encodeBytes(record.keyPair.publicKey.serialize()), PUBLIC_KEY to Base64.encodeBytes(record.keyPair.publicKey.serialize()),
PRIVATE_KEY to Base64.encodeBytes(record.keyPair.privateKey.serialize()) PRIVATE_KEY to Base64.encodeBytes(record.keyPair.privateKey.serialize())
@ -63,8 +63,8 @@ class OneTimePreKeyDatabase(context: Context, databaseHelper: SignalDatabase) :
writableDatabase.replace(TABLE_NAME, null, contentValues) writableDatabase.replace(TABLE_NAME, null, contentValues)
} }
fun delete(accountId: AccountIdentifier, keyId: Int) { fun delete(serviceId: ServiceId, keyId: Int) {
val database = databaseHelper.signalWritableDatabase val database = databaseHelper.signalWritableDatabase
database.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(accountId, keyId)) database.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId))
} }
} }

View file

@ -79,6 +79,7 @@ import org.whispersystems.libsignal.util.guava.Optional
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile import org.whispersystems.signalservice.api.profiles.SignalServiceProfile
import org.whispersystems.signalservice.api.push.ACI import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.PNI import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.storage.SignalAccountRecord import org.whispersystems.signalservice.api.storage.SignalAccountRecord
import org.whispersystems.signalservice.api.storage.SignalContactRecord import org.whispersystems.signalservice.api.storage.SignalContactRecord
@ -110,7 +111,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
const val TABLE_NAME = "recipient" const val TABLE_NAME = "recipient"
const val ID = "_id" const val ID = "_id"
private const val ACI_COLUMN = "uuid" private const val SERVICE_ID = "uuid"
private const val PNI_COLUMN = "pni" private const val PNI_COLUMN = "pni"
private const val USERNAME = "username" private const val USERNAME = "username"
const val PHONE = "phone" const val PHONE = "phone"
@ -171,7 +172,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
""" """
CREATE TABLE $TABLE_NAME ( CREATE TABLE $TABLE_NAME (
$ID INTEGER PRIMARY KEY AUTOINCREMENT, $ID INTEGER PRIMARY KEY AUTOINCREMENT,
$ACI_COLUMN TEXT UNIQUE DEFAULT NULL, $SERVICE_ID TEXT UNIQUE DEFAULT NULL,
$USERNAME TEXT UNIQUE DEFAULT NULL, $USERNAME TEXT UNIQUE DEFAULT NULL,
$PHONE TEXT UNIQUE DEFAULT NULL, $PHONE TEXT UNIQUE DEFAULT NULL,
$EMAIL TEXT UNIQUE DEFAULT NULL, $EMAIL TEXT UNIQUE DEFAULT NULL,
@ -232,7 +233,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
private val RECIPIENT_PROJECTION: Array<String> = arrayOf( private val RECIPIENT_PROJECTION: Array<String> = arrayOf(
ID, ID,
ACI_COLUMN, SERVICE_ID,
PNI_COLUMN, PNI_COLUMN,
USERNAME, USERNAME,
PHONE, PHONE,
@ -367,7 +368,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} }
fun containsPhoneOrUuid(id: String): Boolean { fun containsPhoneOrUuid(id: String): Boolean {
val query = "$ACI_COLUMN = ? OR $PHONE = ?" val query = "$SERVICE_ID = ? OR $PHONE = ?"
val args = arrayOf(id, id) val args = arrayOf(id, id)
readableDatabase.query(TABLE_NAME, arrayOf(ID), query, args, null, null, null).use { cursor -> return cursor != null && cursor.moveToFirst() } readableDatabase.query(TABLE_NAME, arrayOf(ID), query, args, null, null, null).use { cursor -> return cursor != null && cursor.moveToFirst() }
} }
@ -384,20 +385,20 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
return getByColumn(GROUP_ID, groupId.toString()) return getByColumn(GROUP_ID, groupId.toString())
} }
fun getByAci(uuid: ACI): Optional<RecipientId> { fun getByServiceId(serviceId: ServiceId): Optional<RecipientId> {
return getByColumn(ACI_COLUMN, uuid.toString()) return getByColumn(SERVICE_ID, serviceId.toString())
} }
fun getByUsername(username: String): Optional<RecipientId> { fun getByUsername(username: String): Optional<RecipientId> {
return getByColumn(USERNAME, username) return getByColumn(USERNAME, username)
} }
fun getAndPossiblyMerge(aci: ACI?, e164: String?, highTrust: Boolean): RecipientId { fun getAndPossiblyMerge(serviceId: ServiceId?, e164: String?, highTrust: Boolean): RecipientId {
return getAndPossiblyMerge(aci, e164, highTrust, false) return getAndPossiblyMerge(serviceId, e164, highTrust, false)
} }
fun getAndPossiblyMerge(aci: ACI?, e164: String?, highTrust: Boolean, changeSelf: Boolean): RecipientId { fun getAndPossiblyMerge(serviceId: ServiceId?, e164: String?, highTrust: Boolean, changeSelf: Boolean): RecipientId {
require(!(aci == null && e164 == null)) { "Must provide an ACI or E164!" } require(!(serviceId == null && e164 == null)) { "Must provide an ACI or E164!" }
val db = writableDatabase val db = writableDatabase
@ -408,7 +409,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
db.beginTransaction() db.beginTransaction()
try { try {
val fetch: RecipientFetch = fetchRecipient(aci, e164, highTrust, changeSelf) val fetch: RecipientFetch = fetchRecipient(serviceId, e164, highTrust, changeSelf)
if (fetch.logBundle != null) { if (fetch.logBundle != null) {
Log.w(TAG, fetch.toString()) Log.w(TAG, fetch.toString())
@ -432,29 +433,29 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
fetch.id fetch.id
} }
is RecipientFetch.MatchAndUpdateAci -> { is RecipientFetch.MatchAndUpdateAci -> {
markRegistered(fetch.id, fetch.aci) markRegistered(fetch.id, fetch.serviceId)
recipientsNeedingRefresh = listOf(fetch.id) recipientsNeedingRefresh = listOf(fetch.id)
fetch.id fetch.id
} }
is RecipientFetch.MatchAndInsertAci -> { is RecipientFetch.MatchAndInsertAci -> {
val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(null, fetch.aci)) val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(null, fetch.serviceId))
RecipientId.from(id) RecipientId.from(id)
} }
is RecipientFetch.MatchAndMerge -> { is RecipientFetch.MatchAndMerge -> {
remapped = Pair(fetch.e164Id, fetch.aciId) remapped = Pair(fetch.e164Id, fetch.sidId)
val mergedId: RecipientId = merge(fetch.aciId, fetch.e164Id) val mergedId: RecipientId = merge(fetch.sidId, fetch.e164Id)
recipientsNeedingRefresh = listOf(mergedId) recipientsNeedingRefresh = listOf(mergedId)
recipientChangedNumber = fetch.changedNumber recipientChangedNumber = fetch.changedNumber
mergedId mergedId
} }
is RecipientFetch.Insert -> { is RecipientFetch.Insert -> {
val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(fetch.e164, fetch.aci)) val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(fetch.e164, fetch.serviceId))
RecipientId.from(id) RecipientId.from(id)
} }
is RecipientFetch.InsertAndReassignE164 -> { is RecipientFetch.InsertAndReassignE164 -> {
removePhoneNumber(fetch.e164Id, db) removePhoneNumber(fetch.e164Id, db)
recipientsNeedingRefresh = listOf(fetch.e164Id) recipientsNeedingRefresh = listOf(fetch.e164Id)
val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(fetch.e164, fetch.aci)) val id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(fetch.e164, fetch.serviceId))
RecipientId.from(id) RecipientId.from(id)
} }
} }
@ -488,12 +489,12 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} }
} }
private fun fetchRecipient(aci: ACI?, e164: String?, highTrust: Boolean, changeSelf: Boolean): RecipientFetch { private fun fetchRecipient(serviceId: ServiceId?, e164: String?, highTrust: Boolean, changeSelf: Boolean): RecipientFetch {
val byE164 = e164?.let { getByE164(it) } ?: Optional.absent() val byE164 = e164?.let { getByE164(it) } ?: Optional.absent()
val byAci = aci?.let { getByAci(it) } ?: Optional.absent() val byAci = serviceId?.let { getByServiceId(it) } ?: Optional.absent()
var logs = LogBundle( var logs = LogBundle(
byAci = byAci.transform { id -> RecipientLogDetails(id = id) }.orNull(), bySid = byAci.transform { id -> RecipientLogDetails(id = id) }.orNull(),
byE164 = byE164.transform { id -> RecipientLogDetails(id = id) }.orNull(), byE164 = byE164.transform { id -> RecipientLogDetails(id = id) }.orNull(),
label = "L0" label = "L0"
) )
@ -504,9 +505,9 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
if (byAci.isPresent && byE164.isAbsent()) { if (byAci.isPresent && byE164.isAbsent()) {
val aciRecord: RecipientRecord = getRecord(byAci.get()) val aciRecord: RecipientRecord = getRecord(byAci.get())
logs = logs.copy(byAci = aciRecord.toLogDetails()) logs = logs.copy(bySid = aciRecord.toLogDetails())
if (highTrust && e164 != null && (changeSelf || aci != SignalStore.account().aci)) { if (highTrust && e164 != null && (changeSelf || serviceId != SignalStore.account().aci)) {
val changedNumber: RecipientId? = if (aciRecord.e164 != null && aciRecord.e164 != e164) aciRecord.id else null val changedNumber: RecipientId? = if (aciRecord.e164 != null && aciRecord.e164 != e164) aciRecord.id else null
return RecipientFetch.MatchAndUpdateE164(byAci.get(), e164, changedNumber, logs.label("L1")) return RecipientFetch.MatchAndUpdateE164(byAci.get(), e164, changedNumber, logs.label("L1"))
} else if (e164 == null) { } else if (e164 == null) {
@ -520,12 +521,12 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
val e164Record: RecipientRecord = getRecord(byE164.get()) val e164Record: RecipientRecord = getRecord(byE164.get())
logs = logs.copy(byE164 = e164Record.toLogDetails()) logs = logs.copy(byE164 = e164Record.toLogDetails())
if (highTrust && aci != null && e164Record.aci == null) { if (highTrust && serviceId != null && e164Record.serviceId == null) {
return RecipientFetch.MatchAndUpdateAci(byE164.get(), aci, logs.label("L3")) return RecipientFetch.MatchAndUpdateAci(byE164.get(), serviceId, logs.label("L3"))
} else if (highTrust && aci != null && e164Record.aci != SignalStore.account().aci) { } else if (highTrust && serviceId != null && e164Record.serviceId != SignalStore.account().aci) {
return RecipientFetch.InsertAndReassignE164(aci, e164, byE164.get(), logs.label("L4")) return RecipientFetch.InsertAndReassignE164(serviceId, e164, byE164.get(), logs.label("L4"))
} else if (aci != null) { } else if (serviceId != null) {
return RecipientFetch.Insert(aci, null, logs.label("L5")) return RecipientFetch.Insert(serviceId, null, logs.label("L5"))
} else { } else {
return RecipientFetch.Match(byE164.get(), null) return RecipientFetch.Match(byE164.get(), null)
} }
@ -533,9 +534,9 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
if (byAci.isAbsent() && byE164.isAbsent()) { if (byAci.isAbsent() && byE164.isAbsent()) {
if (highTrust) { if (highTrust) {
return RecipientFetch.Insert(aci, e164, logs.label("L6")) return RecipientFetch.Insert(serviceId, e164, logs.label("L6"))
} else if (aci != null) { } else if (serviceId != null) {
return RecipientFetch.Insert(aci, null, logs.label("L7")) return RecipientFetch.Insert(serviceId, null, logs.label("L7"))
} else { } else {
return RecipientFetch.Insert(null, e164, logs.label("L8")) return RecipientFetch.Insert(null, e164, logs.label("L8"))
} }
@ -546,17 +547,17 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
val aciRecord: RecipientRecord = getRecord(byAci.get()) val aciRecord: RecipientRecord = getRecord(byAci.get())
val e164Record: RecipientRecord = getRecord(byE164.get()) val e164Record: RecipientRecord = getRecord(byE164.get())
logs = logs.copy(byAci = aciRecord.toLogDetails(), byE164 = e164Record.toLogDetails()) logs = logs.copy(bySid = aciRecord.toLogDetails(), byE164 = e164Record.toLogDetails())
if (e164Record.aci == null) { if (e164Record.serviceId == null) {
if (highTrust) { if (highTrust) {
val changedNumber: RecipientId? = if (aciRecord.e164 != null) aciRecord.id else null val changedNumber: RecipientId? = if (aciRecord.e164 != null) aciRecord.id else null
return RecipientFetch.MatchAndMerge(aciId = byAci.get(), e164Id = byE164.get(), changedNumber = changedNumber, logs.label("L9")) return RecipientFetch.MatchAndMerge(sidId = byAci.get(), e164Id = byE164.get(), changedNumber = changedNumber, logs.label("L9"))
} else { } else {
return RecipientFetch.Match(byAci.get(), logs.label("L10")) return RecipientFetch.Match(byAci.get(), logs.label("L10"))
} }
} else { } else {
if (highTrust && e164Record.aci != SignalStore.account().aci) { if (highTrust && e164Record.serviceId != SignalStore.account().aci) {
val changedNumber: RecipientId? = if (aciRecord.e164 != null) aciRecord.id else null val changedNumber: RecipientId? = if (aciRecord.e164 != null) aciRecord.id else null
return RecipientFetch.MatchAndReassignE164(id = byAci.get(), e164Id = byE164.get(), e164 = e164!!, changedNumber = changedNumber, logs.label("L11")) return RecipientFetch.MatchAndReassignE164(id = byAci.get(), e164Id = byE164.get(), e164 = e164!!, changedNumber = changedNumber, logs.label("L11"))
} else { } else {
@ -565,8 +566,8 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} }
} }
fun getOrInsertFromAci(aci: ACI): RecipientId { fun getOrInsertFromServiceId(serviceId: ServiceId): RecipientId {
return getOrInsertByColumn(ACI_COLUMN, aci.toString()).recipientId return getOrInsertByColumn(SERVICE_ID, serviceId.toString()).recipientId
} }
fun getOrInsertFromE164(e164: String): RecipientId { fun getOrInsertFromE164(e164: String): RecipientId {
@ -785,13 +786,13 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
val recipientId: RecipientId? val recipientId: RecipientId?
if (id < 0) { if (id < 0) {
Log.w(TAG, "[applyStorageSyncContactInsert] Failed to insert. Possibly merging.") Log.w(TAG, "[applyStorageSyncContactInsert] Failed to insert. Possibly merging.")
recipientId = getAndPossiblyMerge(if (insert.address.hasValidAci()) insert.address.aci else null, insert.address.number.orNull(), true) recipientId = getAndPossiblyMerge(if (insert.address.hasValidServiceId()) insert.address.serviceId else null, insert.address.number.orNull(), true)
db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId)) db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId))
} else { } else {
recipientId = RecipientId.from(id) recipientId = RecipientId.from(id)
} }
if (insert.identityKey.isPresent && insert.address.hasValidAci()) { if (insert.identityKey.isPresent && insert.address.hasValidServiceId()) {
try { try {
val identityKey = IdentityKey(insert.identityKey.get(), 0) val identityKey = IdentityKey(insert.identityKey.get(), 0)
identities.updateIdentityAfterSync(insert.address.identifier, recipientId!!, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(insert.identityState)) identities.updateIdentityAfterSync(insert.address.identifier, recipientId!!, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(insert.identityState))
@ -818,7 +819,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
var recipientId = getByColumn(STORAGE_SERVICE_ID, Base64.encodeBytes(update.old.id.raw)).get() var recipientId = getByColumn(STORAGE_SERVICE_ID, Base64.encodeBytes(update.old.id.raw)).get()
Log.w(TAG, "[applyStorageSyncContactUpdate] Found user $recipientId. Possibly merging.") Log.w(TAG, "[applyStorageSyncContactUpdate] Found user $recipientId. Possibly merging.")
recipientId = getAndPossiblyMerge(if (update.new.address.hasValidAci()) update.new.address.aci else null, update.new.address.number.orNull(), true) recipientId = getAndPossiblyMerge(if (update.new.address.hasValidServiceId()) update.new.address.serviceId else null, update.new.address.number.orNull(), true)
Log.w(TAG, "[applyStorageSyncContactUpdate] Merged into $recipientId") Log.w(TAG, "[applyStorageSyncContactUpdate] Merged into $recipientId")
db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId)) db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId))
@ -834,7 +835,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
try { try {
val oldIdentityRecord = identityStore.getIdentityRecord(recipientId) val oldIdentityRecord = identityStore.getIdentityRecord(recipientId)
if (update.new.identityKey.isPresent && update.new.address.hasValidAci()) { if (update.new.identityKey.isPresent && update.new.address.hasValidServiceId()) {
val identityKey = IdentityKey(update.new.identityKey.get(), 0) val identityKey = IdentityKey(update.new.identityKey.get(), 0)
identities.updateIdentityAfterSync(update.new.address.identifier, recipientId, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(update.new.identityState)) identities.updateIdentityAfterSync(update.new.address.identifier, recipientId, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(update.new.identityState))
} }
@ -982,7 +983,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
private fun getRecordForSync(query: String?, args: Array<String>?): List<RecipientRecord> { private fun getRecordForSync(query: String?, args: Array<String>?): List<RecipientRecord> {
val table = val table =
""" """
$TABLE_NAME LEFT OUTER JOIN ${IdentityDatabase.TABLE_NAME} ON $TABLE_NAME.$ACI_COLUMN = ${IdentityDatabase.TABLE_NAME}.${IdentityDatabase.ADDRESS} $TABLE_NAME LEFT OUTER JOIN ${IdentityDatabase.TABLE_NAME} ON $TABLE_NAME.$SERVICE_ID = ${IdentityDatabase.TABLE_NAME}.${IdentityDatabase.ADDRESS}
LEFT OUTER JOIN ${GroupDatabase.TABLE_NAME} ON $TABLE_NAME.$GROUP_ID = ${GroupDatabase.TABLE_NAME}.${GroupDatabase.GROUP_ID} LEFT OUTER JOIN ${GroupDatabase.TABLE_NAME} ON $TABLE_NAME.$GROUP_ID = ${GroupDatabase.TABLE_NAME}.${GroupDatabase.GROUP_ID}
LEFT OUTER JOIN ${ThreadDatabase.TABLE_NAME} ON $TABLE_NAME.$ID = ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.RECIPIENT_ID} LEFT OUTER JOIN ${ThreadDatabase.TABLE_NAME} ON $TABLE_NAME.$ID = ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.RECIPIENT_ID}
""".trimIndent() """.trimIndent()
@ -1018,7 +1019,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
fun getContactStorageSyncIdsMap(): Map<RecipientId, StorageId> { fun getContactStorageSyncIdsMap(): Map<RecipientId, StorageId> {
val query = """ val query = """
$STORAGE_SERVICE_ID NOT NULL AND ( $STORAGE_SERVICE_ID NOT NULL AND (
($GROUP_TYPE = ? AND $ACI_COLUMN NOT NULL AND $ID != ?) ($GROUP_TYPE = ? AND $SERVICE_ID NOT NULL AND $ID != ?)
OR OR
$GROUP_TYPE IN (?) $GROUP_TYPE IN (?)
) )
@ -1505,7 +1506,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
val selfId = Recipient.self().id val selfId = Recipient.self().id
for ((key, value) in profileKeys) { for ((key, value) in profileKeys) {
val recipientId = getOrInsertFromAci(key) val recipientId = getOrInsertFromServiceId(key)
if (setProfileKeyIfAbsent(recipientId, value)) { if (setProfileKeyIfAbsent(recipientId, value)) {
Log.i(TAG, "Learned new profile key") Log.i(TAG, "Learned new profile key")
updated.add(recipientId) updated.add(recipientId)
@ -1513,7 +1514,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} }
for ((key, value) in authoritativeProfileKeys) { for ((key, value) in authoritativeProfileKeys) {
val recipientId = getOrInsertFromAci(key) val recipientId = getOrInsertFromServiceId(key)
if (selfId == recipientId) { if (selfId == recipientId) {
Log.i(TAG, "Seen authoritative update for self") Log.i(TAG, "Seen authoritative update for self")
@ -1760,7 +1761,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
Log.w(TAG, "[setPhoneNumber] Hit a conflict when trying to update $id. Possibly merging.") Log.w(TAG, "[setPhoneNumber] Hit a conflict when trying to update $id. Possibly merging.")
val existing: RecipientRecord = getRecord(id) val existing: RecipientRecord = getRecord(id)
val newId = getAndPossiblyMerge(existing.aci, e164, true) val newId = getAndPossiblyMerge(existing.serviceId, e164, true)
Log.w(TAG, "[setPhoneNumber] Resulting id: $newId") Log.w(TAG, "[setPhoneNumber] Resulting id: $newId")
db.setTransactionSuccessful() db.setTransactionSuccessful()
@ -1812,7 +1813,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 = getAndPossiblyMerge(Recipient.self().requireAci(), e164, highTrust = true, changeSelf = true) val newId = getAndPossiblyMerge(Recipient.self().requireServiceId(), e164, highTrust = 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")
@ -1874,19 +1875,19 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
/** /**
* @return True if setting the UUID resulted in changed recipientId, otherwise false. * @return True if setting the UUID resulted in changed recipientId, otherwise false.
*/ */
fun markRegistered(id: RecipientId, aci: ACI): Boolean { fun markRegistered(id: RecipientId, serviceId: ServiceId): Boolean {
val db = writableDatabase val db = writableDatabase
db.beginTransaction() db.beginTransaction()
try { try {
markRegisteredOrThrow(id, aci) markRegisteredOrThrow(id, serviceId)
db.setTransactionSuccessful() db.setTransactionSuccessful()
return false return false
} catch (e: SQLiteConstraintException) { } catch (e: SQLiteConstraintException) {
Log.w(TAG, "[markRegistered] Hit a conflict when trying to update $id. Possibly merging.") Log.w(TAG, "[markRegistered] Hit a conflict when trying to update $id. Possibly merging.")
val existing = getRecord(id) val existing = getRecord(id)
val newId = getAndPossiblyMerge(aci, existing.e164, true) val newId = getAndPossiblyMerge(serviceId, existing.e164, true)
Log.w(TAG, "[markRegistered] Merged into $newId") Log.w(TAG, "[markRegistered] Merged into $newId")
db.setTransactionSuccessful() db.setTransactionSuccessful()
@ -1899,10 +1900,10 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
/** /**
* Should only use if you are confident that this shouldn't result in any contact merging. * Should only use if you are confident that this shouldn't result in any contact merging.
*/ */
fun markRegisteredOrThrow(id: RecipientId, aci: ACI) { fun markRegisteredOrThrow(id: RecipientId, serviceId: ServiceId) {
val contentValues = ContentValues(2).apply { val contentValues = ContentValues(2).apply {
put(REGISTERED, RegisteredState.REGISTERED.id) put(REGISTERED, RegisteredState.REGISTERED.id)
put(ACI_COLUMN, aci.toString().toLowerCase()) put(SERVICE_ID, serviceId.toString().toLowerCase())
} }
if (update(id, contentValues)) { if (update(id, contentValues)) {
setStorageIdIfNotSet(id) setStorageIdIfNotSet(id)
@ -1920,7 +1921,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} }
} }
fun bulkUpdatedRegisteredStatus(registered: Map<RecipientId, ACI?>, unregistered: Collection<RecipientId>) { fun bulkUpdatedRegisteredStatus(registered: Map<RecipientId, ServiceId?>, unregistered: Collection<RecipientId>) {
val db = writableDatabase val db = writableDatabase
db.beginTransaction() db.beginTransaction()
@ -1929,7 +1930,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
val values = ContentValues(2).apply { val values = ContentValues(2).apply {
put(REGISTERED, RegisteredState.REGISTERED.id) put(REGISTERED, RegisteredState.REGISTERED.id)
if (aci != null) { if (aci != null) {
put(ACI_COLUMN, aci.toString().toLowerCase()) put(SERVICE_ID, aci.toString().toLowerCase())
} }
} }
@ -1972,12 +1973,12 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
db.beginTransaction() db.beginTransaction()
try { try {
for ((e164, aci) in mapping) { for ((e164, aci) in mapping) {
var aciEntry = if (aci != null) getByAci(aci) else Optional.absent() var aciEntry = if (aci != null) getByServiceId(aci) else Optional.absent()
if (aciEntry.isPresent) { if (aciEntry.isPresent) {
val idChanged = setPhoneNumber(aciEntry.get(), e164) val idChanged = setPhoneNumber(aciEntry.get(), e164)
if (idChanged) { if (idChanged) {
aciEntry = getByAci(aci!!) aciEntry = getByServiceId(aci!!)
} }
} }
@ -2272,7 +2273,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
.toList() .toList()
val blockedUuid = blocked val blockedUuid = blocked
.map { b: SignalServiceAddress -> b.aci.toString().toLowerCase() } .map { b: SignalServiceAddress -> b.serviceId.toString().toLowerCase() }
.toList() .toList()
val db = writableDatabase val db = writableDatabase
@ -2293,7 +2294,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} }
for (uuid in blockedUuid) { for (uuid in blockedUuid) {
db.update(TABLE_NAME, setBlocked, "$ACI_COLUMN = ?", arrayOf(uuid)) db.update(TABLE_NAME, setBlocked, "$SERVICE_ID = ?", arrayOf(uuid))
} }
val groupIdStrings: MutableList<V1> = ArrayList(groupIds.size) val groupIdStrings: MutableList<V1> = ArrayList(groupIds.size)
@ -2604,10 +2605,10 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} }
// Sessions // Sessions
val localAci: ACI = SignalStore.account().aci!! val localAci: ACI = SignalStore.account().requireAci()
val sessionDatabase = sessions val sessionDatabase = sessions
val hasE164Session = sessionDatabase.getAllFor(localAci, e164Record.e164).isNotEmpty() val hasE164Session = sessionDatabase.getAllFor(localAci, e164Record.e164).isNotEmpty()
val hasAciSession = sessionDatabase.getAllFor(localAci, aciRecord.aci.toString()).isNotEmpty() val hasAciSession = sessionDatabase.getAllFor(localAci, aciRecord.serviceId.toString()).isNotEmpty()
if (hasE164Session && hasAciSession) { if (hasE164Session && hasAciSession) {
Log.w(TAG, "Had a session for both users. Deleting the E164.", true) Log.w(TAG, "Had a session for both users. Deleting the E164.", true)
@ -2615,7 +2616,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
} else if (hasE164Session && !hasAciSession) { } else if (hasE164Session && !hasAciSession) {
Log.w(TAG, "Had a session for E164, but not ACI. Re-assigning to the ACI.", true) Log.w(TAG, "Had a session for E164, but not ACI. Re-assigning to the ACI.", true)
val values = ContentValues().apply { val values = ContentValues().apply {
put(SessionDatabase.ADDRESS, aciRecord.aci.toString()) put(SessionDatabase.ADDRESS, aciRecord.serviceId.toString())
} }
db.update(SessionDatabase.TABLE_NAME, values, "${SessionDatabase.ACCOUNT_ID} = ? AND ${SessionDatabase.ADDRESS} = ?", SqlUtil.buildArgs(localAci, e164Record.e164)) db.update(SessionDatabase.TABLE_NAME, values, "${SessionDatabase.ACCOUNT_ID} = ? AND ${SessionDatabase.ADDRESS} = ?", SqlUtil.buildArgs(localAci, e164Record.e164))
} else if (!hasE164Session && hasAciSession) { } else if (!hasE164Session && hasAciSession) {
@ -2694,11 +2695,11 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
check(writableDatabase.inTransaction()) { "Must be in a transaction!" } check(writableDatabase.inTransaction()) { "Must be in a transaction!" }
} }
private fun buildContentValuesForNewUser(e164: String?, aci: ACI?): ContentValues { private fun buildContentValuesForNewUser(e164: String?, serviceId: ServiceId?): ContentValues {
val values = ContentValues() val values = ContentValues()
values.put(PHONE, e164) values.put(PHONE, e164)
if (aci != null) { if (serviceId != null) {
values.put(ACI_COLUMN, aci.toString().toLowerCase()) values.put(SERVICE_ID, serviceId.toString().toLowerCase())
values.put(REGISTERED, RegisteredState.REGISTERED.id) values.put(REGISTERED, RegisteredState.REGISTERED.id)
values.put(STORAGE_SERVICE_ID, Base64.encodeBytes(StorageSyncHelper.generateKey())) values.put(STORAGE_SERVICE_ID, Base64.encodeBytes(StorageSyncHelper.generateKey()))
values.put(AVATAR_COLOR, AvatarColor.random().serialize()) values.put(AVATAR_COLOR, AvatarColor.random().serialize())
@ -2711,8 +2712,8 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
val profileName = ProfileName.fromParts(contact.givenName.orNull(), contact.familyName.orNull()) val profileName = ProfileName.fromParts(contact.givenName.orNull(), contact.familyName.orNull())
val username = contact.username.orNull() val username = contact.username.orNull()
if (contact.address.hasValidAci()) { if (contact.address.hasValidServiceId()) {
put(ACI_COLUMN, contact.address.aci.toString()) put(SERVICE_ID, contact.address.serviceId.toString())
} }
put(PHONE, contact.address.number.orNull()) put(PHONE, contact.address.number.orNull())
@ -2845,7 +2846,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
return RecipientRecord( return RecipientRecord(
id = recipientId, id = recipientId,
aci = ACI.parseOrNull(cursor.requireString(ACI_COLUMN)), serviceId = ACI.parseOrNull(cursor.requireString(SERVICE_ID)),
pni = PNI.parseOrNull(cursor.requireString(PNI_COLUMN)), pni = PNI.parseOrNull(cursor.requireString(PNI_COLUMN)),
username = cursor.requireString(USERNAME), username = cursor.requireString(USERNAME),
e164 = cursor.requireString(PHONE), e164 = cursor.requireString(PHONE),
@ -3045,7 +3046,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
private fun RecipientRecord.toLogDetails(): RecipientLogDetails { private fun RecipientRecord.toLogDetails(): RecipientLogDetails {
return RecipientLogDetails( return RecipientLogDetails(
id = this.id, id = this.id,
aci = this.aci, serviceId = this.serviceId,
e164 = this.e164 e164 = this.e164
) )
} }
@ -3357,27 +3358,27 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
/** /**
* We found a matching recipient and can update them with a new ACI. * We found a matching recipient and can update them with a new ACI.
*/ */
data class MatchAndUpdateAci(val id: RecipientId, val aci: ACI, val bundle: LogBundle) : RecipientFetch(bundle) data class MatchAndUpdateAci(val id: RecipientId, val serviceId: ServiceId, val bundle: LogBundle) : RecipientFetch(bundle)
/** /**
* We found a matching recipient and can insert an ACI as a *new user*. * We found a matching recipient and can insert an ACI as a *new user*.
*/ */
data class MatchAndInsertAci(val id: RecipientId, val aci: ACI, val bundle: LogBundle) : RecipientFetch(bundle) data class MatchAndInsertAci(val id: RecipientId, val serviceId: ServiceId, val bundle: LogBundle) : RecipientFetch(bundle)
/** /**
* The ACI maps to ACI-only recipient, and the E164 maps to a different E164-only recipient. We need to merge the two together. * The ACI maps to ACI-only recipient, and the E164 maps to a different E164-only recipient. We need to merge the two together.
*/ */
data class MatchAndMerge(val aciId: RecipientId, val e164Id: RecipientId, val changedNumber: RecipientId?, val bundle: LogBundle) : RecipientFetch(bundle) data class MatchAndMerge(val sidId: RecipientId, val e164Id: RecipientId, val changedNumber: RecipientId?, val bundle: LogBundle) : RecipientFetch(bundle)
/** /**
* We don't have a matching recipient, so we need to insert one. * We don't have a matching recipient, so we need to insert one.
*/ */
data class Insert(val aci: ACI?, val e164: String?, val bundle: LogBundle) : RecipientFetch(bundle) data class Insert(val serviceId: ServiceId?, val e164: String?, val bundle: LogBundle) : RecipientFetch(bundle)
/** /**
* We need to create a new recipient and give it the E164 of an existing recipient. * We need to create a new recipient and give it the E164 of an existing recipient.
*/ */
data class InsertAndReassignE164(val aci: ACI?, val e164: String?, val e164Id: RecipientId, val bundle: LogBundle) : RecipientFetch(bundle) data class InsertAndReassignE164(val serviceId: ServiceId?, val e164: String?, val e164Id: RecipientId, val bundle: LogBundle) : RecipientFetch(bundle)
} }
/** /**
@ -3385,9 +3386,9 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
*/ */
private data class LogBundle( private data class LogBundle(
val label: String, val label: String,
val aci: ACI? = null, val serviceId: ServiceId? = null,
val e164: String? = null, val e164: String? = null,
val byAci: RecipientLogDetails? = null, val bySid: RecipientLogDetails? = null,
val byE164: RecipientLogDetails? = null val byE164: RecipientLogDetails? = null
) { ) {
fun label(label: String): LogBundle { fun label(label: String): LogBundle {
@ -3400,7 +3401,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
*/ */
private data class RecipientLogDetails( private data class RecipientLogDetails(
val id: RecipientId, val id: RecipientId,
val aci: ACI? = null, val serviceId: ServiceId? = null,
val e164: String? = null val e164: String? = null
) )
} }

View file

@ -133,7 +133,7 @@ public class SenderKeyDatabase extends Database {
public Cursor getAllCreatedBySelf() { public Cursor getAllCreatedBySelf() {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String query = ADDRESS + " = ?"; String query = ADDRESS + " = ?";
String[] args = SqlUtil.buildArgs(Recipient.self().requireAci()); String[] args = SqlUtil.buildArgs(Recipient.self().requireServiceId());
return db.query(TABLE_NAME, new String[]{ ID, DISTRIBUTION_ID, CREATED_AT }, query, args, null, null, CREATED_AT + " DESC"); return db.query(TABLE_NAME, new String[]{ ID, DISTRIBUTION_ID, CREATED_AT }, query, args, null, null, CREATED_AT + " DESC");
} }

View file

@ -145,8 +145,8 @@ public class SenderKeySharedDatabase extends Database {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
Recipient recipient = Recipient.resolved(recipientId); Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasAci()) { if (recipient.hasServiceId()) {
db.delete(TABLE_NAME, ADDRESS + " = ?", SqlUtil.buildArgs(recipient.requireAci().toString())); db.delete(TABLE_NAME, ADDRESS + " = ?", SqlUtil.buildArgs(recipient.requireServiceId().toString()));
} else { } else {
Log.w(TAG, "Recipient doesn't have a UUID! " + recipientId); Log.w(TAG, "Recipient doesn't have a UUID! " + recipientId);
} }

View file

@ -6,7 +6,7 @@ import org.thoughtcrime.securesms.util.CursorUtil
import org.thoughtcrime.securesms.util.SqlUtil import org.thoughtcrime.securesms.util.SqlUtil
import org.whispersystems.libsignal.SignalProtocolAddress import org.whispersystems.libsignal.SignalProtocolAddress
import org.whispersystems.libsignal.state.SessionRecord import org.whispersystems.libsignal.state.SessionRecord
import org.whispersystems.signalservice.api.push.AccountIdentifier import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.push.SignalServiceAddress
import java.io.IOException import java.io.IOException
import java.util.ArrayList import java.util.ArrayList
@ -36,12 +36,12 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
""" """
} }
fun store(accountId: AccountIdentifier, address: SignalProtocolAddress, record: SessionRecord) { fun store(serviceId: ServiceId, address: SignalProtocolAddress, record: SessionRecord) {
require(address.name[0] != '+') { "Cannot insert an e164 into this table!" } require(address.name[0] != '+') { "Cannot insert an e164 into this table!" }
writableDatabase.compileStatement("INSERT INTO $TABLE_NAME ($ACCOUNT_ID, $ADDRESS, $DEVICE, $RECORD) VALUES (?, ?, ?, ?) ON CONFLICT ($ACCOUNT_ID, $ADDRESS, $DEVICE) DO UPDATE SET $RECORD = excluded.$RECORD").use { statement -> writableDatabase.compileStatement("INSERT INTO $TABLE_NAME ($ACCOUNT_ID, $ADDRESS, $DEVICE, $RECORD) VALUES (?, ?, ?, ?) ON CONFLICT ($ACCOUNT_ID, $ADDRESS, $DEVICE) DO UPDATE SET $RECORD = excluded.$RECORD").use { statement ->
statement.apply { statement.apply {
bindString(1, accountId.toString()) bindString(1, serviceId.toString())
bindString(2, address.name) bindString(2, address.name)
bindLong(3, address.deviceId.toLong()) bindLong(3, address.deviceId.toLong())
bindBlob(4, record.serialize()) bindBlob(4, record.serialize())
@ -50,10 +50,10 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
} }
} }
fun load(accountId: AccountIdentifier, address: SignalProtocolAddress): SessionRecord? { fun load(serviceId: ServiceId, address: SignalProtocolAddress): SessionRecord? {
val projection = arrayOf(RECORD) val projection = arrayOf(RECORD)
val selection = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?" val selection = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?"
val args = SqlUtil.buildArgs(accountId, address.name, address.deviceId) val args = SqlUtil.buildArgs(serviceId, address.name, address.deviceId)
readableDatabase.query(TABLE_NAME, projection, selection, args, null, null, null).use { cursor -> readableDatabase.query(TABLE_NAME, projection, selection, args, null, null, null).use { cursor ->
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@ -68,14 +68,14 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
return null return null
} }
fun load(accountId: AccountIdentifier, addresses: List<SignalProtocolAddress>): List<SessionRecord?> { fun load(serviceId: ServiceId, addresses: List<SignalProtocolAddress>): List<SessionRecord?> {
val projection = arrayOf(ADDRESS, DEVICE, RECORD) val projection = arrayOf(ADDRESS, DEVICE, RECORD)
val query = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?" val query = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?"
val args: MutableList<Array<String>> = ArrayList(addresses.size) val args: MutableList<Array<String>> = ArrayList(addresses.size)
val sessions: HashMap<SignalProtocolAddress, SessionRecord?> = LinkedHashMap(addresses.size) val sessions: HashMap<SignalProtocolAddress, SessionRecord?> = LinkedHashMap(addresses.size)
for (address in addresses) { for (address in addresses) {
args.add(SqlUtil.buildArgs(accountId, address.name, address.deviceId)) args.add(SqlUtil.buildArgs(serviceId, address.name, address.deviceId))
sessions[address] = null sessions[address] = null
} }
@ -97,10 +97,10 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
return sessions.values.toList() return sessions.values.toList()
} }
fun getAllFor(accountId: AccountIdentifier, addressName: String): List<SessionRow> { fun getAllFor(serviceId: ServiceId, addressName: String): List<SessionRow> {
val results: MutableList<SessionRow> = mutableListOf() val results: MutableList<SessionRow> = mutableListOf()
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $ADDRESS = ?", SqlUtil.buildArgs(accountId, addressName), null, null, null).use { cursor -> readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $ADDRESS = ?", SqlUtil.buildArgs(serviceId, addressName), null, null, null).use { cursor ->
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
try { try {
results.add( results.add(
@ -118,12 +118,12 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
return results return results
} }
fun getAllFor(accountId: AccountIdentifier, addressNames: List<String?>): List<SessionRow> { fun getAllFor(serviceId: ServiceId, addressNames: List<String?>): List<SessionRow> {
val query: SqlUtil.Query = SqlUtil.buildCollectionQuery(ADDRESS, addressNames) val query: SqlUtil.Query = SqlUtil.buildCollectionQuery(ADDRESS, addressNames)
val results: MutableList<SessionRow> = LinkedList() val results: MutableList<SessionRow> = LinkedList()
val queryString = "$ACCOUNT_ID = ? AND (${query.where})" val queryString = "$ACCOUNT_ID = ? AND (${query.where})"
val queryArgs: Array<String> = arrayOf(accountId.toString()) + query.whereArgs val queryArgs: Array<String> = arrayOf(serviceId.toString()) + query.whereArgs
readableDatabase.query(TABLE_NAME, null, queryString, queryArgs, null, null, null).use { cursor -> readableDatabase.query(TABLE_NAME, null, queryString, queryArgs, null, null, null).use { cursor ->
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
@ -143,10 +143,10 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
return results return results
} }
fun getAll(accountId: AccountIdentifier): List<SessionRow> { fun getAll(serviceId: ServiceId): List<SessionRow> {
val results: MutableList<SessionRow> = mutableListOf() val results: MutableList<SessionRow> = mutableListOf()
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(accountId), null, null, null).use { cursor -> readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(serviceId), null, null, null).use { cursor ->
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
try { try {
results.add( results.add(
@ -164,10 +164,10 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
return results return results
} }
fun getSubDevices(accountId: AccountIdentifier, addressName: String): List<Int> { fun getSubDevices(serviceId: ServiceId, addressName: String): List<Int> {
val projection = arrayOf(DEVICE) val projection = arrayOf(DEVICE)
val selection = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE != ?" val selection = "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE != ?"
val args = SqlUtil.buildArgs(accountId, addressName, SignalServiceAddress.DEFAULT_DEVICE_ID) val args = SqlUtil.buildArgs(serviceId, addressName, SignalServiceAddress.DEFAULT_DEVICE_ID)
val results: MutableList<Int> = mutableListOf() val results: MutableList<Int> = mutableListOf()
@ -179,17 +179,17 @@ class SessionDatabase(context: Context, databaseHelper: SignalDatabase) : Databa
return results return results
} }
fun delete(accountId: AccountIdentifier, address: SignalProtocolAddress) { fun delete(serviceId: ServiceId, address: SignalProtocolAddress) {
writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?", SqlUtil.buildArgs(accountId, address.name, address.deviceId)) writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $ADDRESS = ? AND $DEVICE = ?", SqlUtil.buildArgs(serviceId, address.name, address.deviceId))
} }
fun deleteAllFor(accountId: AccountIdentifier, addressName: String) { fun deleteAllFor(serviceId: ServiceId, addressName: String) {
writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $ADDRESS = ?", SqlUtil.buildArgs(accountId, addressName)) writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $ADDRESS = ?", SqlUtil.buildArgs(serviceId, addressName))
} }
fun hasSessionFor(accountId: AccountIdentifier, addressName: String): Boolean { fun hasSessionFor(serviceId: ServiceId, addressName: String): Boolean {
val query = "$ACCOUNT_ID = ? AND $ADDRESS = ?" val query = "$ACCOUNT_ID = ? AND $ADDRESS = ?"
val args = SqlUtil.buildArgs(accountId, addressName) val args = SqlUtil.buildArgs(serviceId, addressName)
readableDatabase.query(TABLE_NAME, arrayOf("1"), query, args, null, null, null, "1").use { cursor -> readableDatabase.query(TABLE_NAME, arrayOf("1"), query, args, null, null, null, "1").use { cursor ->
return cursor.moveToFirst() return cursor.moveToFirst()
} }

View file

@ -9,7 +9,7 @@ import org.whispersystems.libsignal.InvalidKeyException
import org.whispersystems.libsignal.ecc.Curve import org.whispersystems.libsignal.ecc.Curve
import org.whispersystems.libsignal.ecc.ECKeyPair import org.whispersystems.libsignal.ecc.ECKeyPair
import org.whispersystems.libsignal.state.SignedPreKeyRecord import org.whispersystems.libsignal.state.SignedPreKeyRecord
import org.whispersystems.signalservice.api.push.AccountIdentifier import org.whispersystems.signalservice.api.push.ServiceId
import java.io.IOException import java.io.IOException
import java.util.LinkedList import java.util.LinkedList
@ -39,8 +39,8 @@ class SignedPreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : D
""" """
} }
fun get(accountId: AccountIdentifier, keyId: Int): SignedPreKeyRecord? { fun get(serviceId: ServiceId, keyId: Int): SignedPreKeyRecord? {
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(accountId, keyId), null, null, null).use { cursor -> readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId), null, null, null).use { cursor ->
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
try { try {
val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0) val publicKey = Curve.decodePoint(Base64.decode(cursor.requireNonNullString(PUBLIC_KEY)), 0)
@ -58,10 +58,10 @@ class SignedPreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : D
return null return null
} }
fun getAll(accountId: AccountIdentifier): List<SignedPreKeyRecord> { fun getAll(serviceId: ServiceId): List<SignedPreKeyRecord> {
val results: MutableList<SignedPreKeyRecord> = LinkedList() val results: MutableList<SignedPreKeyRecord> = LinkedList()
readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(accountId), null, null, null).use { cursor -> readableDatabase.query(TABLE_NAME, null, "$ACCOUNT_ID = ?", SqlUtil.buildArgs(serviceId), null, null, null).use { cursor ->
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
try { try {
val keyId = cursor.requireInt(KEY_ID) val keyId = cursor.requireInt(KEY_ID)
@ -81,9 +81,9 @@ class SignedPreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : D
return results return results
} }
fun insert(accountId: AccountIdentifier, keyId: Int, record: SignedPreKeyRecord) { fun insert(serviceId: ServiceId, keyId: Int, record: SignedPreKeyRecord) {
val contentValues = contentValuesOf( val contentValues = contentValuesOf(
ACCOUNT_ID to accountId.toString(), ACCOUNT_ID to serviceId.toString(),
KEY_ID to keyId, KEY_ID to keyId,
PUBLIC_KEY to Base64.encodeBytes(record.keyPair.publicKey.serialize()), PUBLIC_KEY to Base64.encodeBytes(record.keyPair.publicKey.serialize()),
PRIVATE_KEY to Base64.encodeBytes(record.keyPair.privateKey.serialize()), PRIVATE_KEY to Base64.encodeBytes(record.keyPair.privateKey.serialize()),
@ -93,7 +93,7 @@ class SignedPreKeyDatabase(context: Context, databaseHelper: SignalDatabase) : D
writableDatabase.replace(TABLE_NAME, null, contentValues) writableDatabase.replace(TABLE_NAME, null, contentValues)
} }
fun delete(accountId: AccountIdentifier, keyId: Int) { fun delete(serviceId: ServiceId, keyId: Int) {
writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(accountId, keyId)) writableDatabase.delete(TABLE_NAME, "$ACCOUNT_ID = ? AND $KEY_ID = ?", SqlUtil.buildArgs(serviceId, keyId))
} }
} }

View file

@ -719,11 +719,11 @@ public class SmsDatabase extends MessageDatabase {
if (!peerEraIdSameAsPrevious && !Util.isEmpty(peekGroupCallEraId)) { if (!peerEraIdSameAsPrevious && !Util.isEmpty(peekGroupCallEraId)) {
Recipient self = Recipient.self(); Recipient self = Recipient.self();
boolean markRead = peekJoinedUuids.contains(self.requireAci().uuid()) || self.getId().equals(sender); boolean markRead = peekJoinedUuids.contains(self.requireServiceId().uuid()) || self.getId().equals(sender);
byte[] updateDetails = GroupCallUpdateDetails.newBuilder() byte[] updateDetails = GroupCallUpdateDetails.newBuilder()
.setEraId(Util.emptyIfNull(peekGroupCallEraId)) .setEraId(Util.emptyIfNull(peekGroupCallEraId))
.setStartedCallUuid(Recipient.resolved(sender).requireAci().toString()) .setStartedCallUuid(Recipient.resolved(sender).requireServiceId().toString())
.setStartedCallTimestamp(timestamp) .setStartedCallTimestamp(timestamp)
.addAllInCallUuids(Stream.of(peekJoinedUuids).map(UUID::toString).toList()) .addAllInCallUuids(Stream.of(peekJoinedUuids).map(UUID::toString).toList())
.setIsCallFull(isCallFull) .setIsCallFull(isCallFull)
@ -800,7 +800,7 @@ public class SmsDatabase extends MessageDatabase {
if (!sameEraId && !Util.isEmpty(messageGroupCallEraId)) { if (!sameEraId && !Util.isEmpty(messageGroupCallEraId)) {
byte[] updateDetails = GroupCallUpdateDetails.newBuilder() byte[] updateDetails = GroupCallUpdateDetails.newBuilder()
.setEraId(Util.emptyIfNull(messageGroupCallEraId)) .setEraId(Util.emptyIfNull(messageGroupCallEraId))
.setStartedCallUuid(Recipient.resolved(sender).requireAci().toString()) .setStartedCallUuid(Recipient.resolved(sender).requireServiceId().toString())
.setStartedCallTimestamp(timestamp) .setStartedCallTimestamp(timestamp)
.addAllInCallUuids(Collections.emptyList()) .addAllInCallUuids(Collections.emptyList())
.setIsCallFull(false) .setIsCallFull(false)
@ -849,7 +849,7 @@ public class SmsDatabase extends MessageDatabase {
} }
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(record.getBody()); GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(record.getBody());
boolean containsSelf = peekJoinedUuids.contains(Recipient.self().requireAci().uuid()); boolean containsSelf = peekJoinedUuids.contains(Recipient.self().requireServiceId().uuid());
sameEraId = groupCallUpdateDetails.getEraId().equals(peekGroupCallEraId) && !Util.isEmpty(peekGroupCallEraId); sameEraId = groupCallUpdateDetails.getEraId().equals(peekGroupCallEraId) && !Util.isEmpty(peekGroupCallEraId);

View file

@ -1208,7 +1208,7 @@ public class ThreadDatabase extends Database {
Recipient pinnedRecipient; Recipient pinnedRecipient;
if (pinned.getContact().isPresent()) { if (pinned.getContact().isPresent()) {
pinnedRecipient = Recipient.externalPush(context, pinned.getContact().get()); pinnedRecipient = Recipient.externalPush(pinned.getContact().get());
} else if (pinned.getGroupV1Id().isPresent()) { } else if (pinned.getGroupV1Id().isPresent()) {
try { try {
pinnedRecipient = Recipient.externalGroupExact(context, GroupId.v1(pinned.getGroupV1Id().get())); pinnedRecipient = Recipient.externalGroupExact(context, GroupId.v1(pinned.getGroupV1Id().get()));

View file

@ -6,11 +6,12 @@ import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails; import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -22,13 +23,13 @@ import java.util.Objects;
*/ */
public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFactory { public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFactory {
private final Context context; private final Context context;
private final List<ACI> joinedMembers; private final List<ServiceId> joinedMembers;
private final boolean withTime; private final boolean withTime;
private final GroupCallUpdateDetails groupCallUpdateDetails; private final GroupCallUpdateDetails groupCallUpdateDetails;
private final ACI selfAci; private final ACI selfAci;
public GroupCallUpdateMessageFactory(@NonNull Context context, public GroupCallUpdateMessageFactory(@NonNull Context context,
@NonNull List<ACI> joinedMembers, @NonNull List<ServiceId> joinedMembers,
boolean withTime, boolean withTime,
@NonNull GroupCallUpdateDetails groupCallUpdateDetails) @NonNull GroupCallUpdateDetails groupCallUpdateDetails)
{ {
@ -36,7 +37,7 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFa
this.joinedMembers = new ArrayList<>(joinedMembers); this.joinedMembers = new ArrayList<>(joinedMembers);
this.withTime = withTime; this.withTime = withTime;
this.groupCallUpdateDetails = groupCallUpdateDetails; this.groupCallUpdateDetails = groupCallUpdateDetails;
this.selfAci = Recipient.self().requireAci(); this.selfAci = SignalStore.account().requireAci();
boolean removed = this.joinedMembers.remove(selfAci); boolean removed = this.joinedMembers.remove(selfAci);
if (removed) { if (removed) {
@ -87,12 +88,12 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFa
} }
} }
private @NonNull String describe(@NonNull ACI aci) { private @NonNull String describe(@NonNull ServiceId serviceId) {
if (aci.isUnknown()) { if (serviceId.isUnknown()) {
return context.getString(R.string.MessageRecord_unknown); return context.getString(R.string.MessageRecord_unknown);
} }
Recipient recipient = Recipient.resolved(RecipientId.from(aci, null)); Recipient recipient = Recipient.resolved(RecipientId.from(serviceId, null));
if (recipient.isSelf()) { if (recipient.isSelf()) {
return context.getString(R.string.MessageRecord_you); return context.getString(R.string.MessageRecord_you);

View file

@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.util.StringUtil;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Arrays; import java.util.Arrays;
@ -746,11 +747,11 @@ final class GroupsV2UpdateMessageProducer {
/** /**
* Map an ACI to a string that describes the group member. * Map an ACI to a string that describes the group member.
* @param aci * @param serviceId
*/ */
@NonNull @NonNull
@WorkerThread @WorkerThread
String describe(@NonNull ACI aci); String describe(@NonNull ServiceId serviceId);
} }
private interface StringFactory1Arg { private interface StringFactory1Arg {
@ -771,9 +772,9 @@ final class GroupsV2UpdateMessageProducer {
@NonNull StringFactory1Arg stringFactory, @NonNull StringFactory1Arg stringFactory,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
ACI aci1 = ACI.fromByteStringOrUnknown(uuid1Bytes); ServiceId serviceId = ServiceId.fromByteStringOrUnknown(uuid1Bytes);
return UpdateDescription.mentioning(Collections.singletonList(aci1), () -> stringFactory.create(descriptionStrategy.describe(aci1)), iconResource); return UpdateDescription.mentioning(Collections.singletonList(serviceId), () -> stringFactory.create(descriptionStrategy.describe(serviceId)), iconResource);
} }
private UpdateDescription updateDescription(@NonNull ByteString uuid1Bytes, private UpdateDescription updateDescription(@NonNull ByteString uuid1Bytes,
@ -781,9 +782,9 @@ final class GroupsV2UpdateMessageProducer {
@NonNull StringFactory2Args stringFactory, @NonNull StringFactory2Args stringFactory,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
ACI aci1 = ACI.fromByteStringOrUnknown(uuid1Bytes); ServiceId sid1 = ServiceId.fromByteStringOrUnknown(uuid1Bytes);
ACI aci2 = ACI.fromByteStringOrUnknown(uuid2Bytes); ServiceId sid2 = ServiceId.fromByteStringOrUnknown(uuid2Bytes);
return UpdateDescription.mentioning(Arrays.asList(aci1, aci2), () -> stringFactory.create(descriptionStrategy.describe(aci1), descriptionStrategy.describe(aci2)), iconResource); return UpdateDescription.mentioning(Arrays.asList(sid1, sid2), () -> stringFactory.create(descriptionStrategy.describe(sid1), descriptionStrategy.describe(sid2)), iconResource);
} }
} }

View file

@ -60,7 +60,7 @@ import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Function; import org.whispersystems.libsignal.util.guava.Function;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException; import java.io.IOException;
@ -253,7 +253,7 @@ public abstract class MessageRecord extends DisplayRecord {
private static boolean selfCreatedGroup(@NonNull DecryptedGroupChange change) { private static boolean selfCreatedGroup(@NonNull DecryptedGroupChange change) {
return change.getRevision() == 0 && return change.getRevision() == 0 &&
change.getEditor().equals(UuidUtil.toByteString(Recipient.self().requireAci().uuid())); change.getEditor().equals(UuidUtil.toByteString(Recipient.self().requireServiceId().uuid()));
} }
public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull String body) { public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull String body) {
@ -261,7 +261,7 @@ public abstract class MessageRecord extends DisplayRecord {
ShortStringDescriptionStrategy descriptionStrategy = new ShortStringDescriptionStrategy(context); ShortStringDescriptionStrategy descriptionStrategy = new ShortStringDescriptionStrategy(context);
byte[] decoded = Base64.decode(body); byte[] decoded = Base64.decode(body);
DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded); DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded);
GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, descriptionStrategy, Recipient.self().requireAci().uuid()); GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, descriptionStrategy, Recipient.self().requireServiceId().uuid());
if (decryptedGroupV2Context.hasChange() && (decryptedGroupV2Context.getGroupState().getRevision() != 0 || decryptedGroupV2Context.hasPreviousGroupState())) { if (decryptedGroupV2Context.hasChange() && (decryptedGroupV2Context.getGroupState().getRevision() != 0 || decryptedGroupV2Context.hasPreviousGroupState())) {
return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(decryptedGroupV2Context.getPreviousGroupState(), decryptedGroupV2Context.getChange())); return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(decryptedGroupV2Context.getPreviousGroupState(), decryptedGroupV2Context.getChange()));
@ -292,7 +292,7 @@ public abstract class MessageRecord extends DisplayRecord {
} }
DecryptedGroup groupState = decryptedGroupV2Context.getGroupState(); DecryptedGroup groupState = decryptedGroupV2Context.getGroupState();
boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), Recipient.self().requireAci().uuid()).isPresent(); boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), Recipient.self().requireServiceId().uuid()).isPresent();
if (decryptedGroupV2Context.hasChange()) { if (decryptedGroupV2Context.hasChange()) {
UUID changeEditor = UuidUtil.fromByteStringOrNull(decryptedGroupV2Context.getChange().getEditor()); UUID changeEditor = UuidUtil.fromByteStringOrNull(decryptedGroupV2Context.getChange().getEditor());
@ -314,7 +314,7 @@ public abstract class MessageRecord extends DisplayRecord {
@NonNull Function<Recipient, String> stringGenerator, @NonNull Function<Recipient, String> stringGenerator,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
return UpdateDescription.mentioning(Collections.singletonList(recipient.getAci().or(ACI.UNKNOWN)), return UpdateDescription.mentioning(Collections.singletonList(recipient.getServiceId().or(ServiceId.UNKNOWN)),
() -> stringGenerator.apply(recipient.resolve()), () -> stringGenerator.apply(recipient.resolve()),
iconResource); iconResource);
} }
@ -382,11 +382,11 @@ public abstract class MessageRecord extends DisplayRecord {
public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) { public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) {
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body); GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body);
List<ACI> joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList()) List<ServiceId> joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList())
.map(UuidUtil::parseOrNull) .map(UuidUtil::parseOrNull)
.withoutNulls() .withoutNulls()
.map(ACI::from) .map(ServiceId::from)
.toList(); .toList();
UpdateDescription.StringFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails); UpdateDescription.StringFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails);
@ -421,11 +421,11 @@ public abstract class MessageRecord extends DisplayRecord {
} }
@Override @Override
public @NonNull String describe(@NonNull ACI aci) { public @NonNull String describe(@NonNull ServiceId serviceId) {
if (aci.isUnknown()) { if (serviceId.isUnknown()) {
return context.getString(R.string.MessageRecord_unknown); return context.getString(R.string.MessageRecord_unknown);
} }
return Recipient.resolved(RecipientId.from(aci, null)).getDisplayName(context); return Recipient.resolved(RecipientId.from(serviceId, null)).getDisplayName(context);
} }
} }

View file

@ -20,15 +20,15 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
import org.whispersystems.libsignal.util.guava.Optional import org.whispersystems.libsignal.util.guava.Optional
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.PNI import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.ServiceId
/** /**
* Database model for [RecipientDatabase]. * Database model for [RecipientDatabase].
*/ */
data class RecipientRecord( data class RecipientRecord(
val id: RecipientId, val id: RecipientId,
val aci: ACI?, val serviceId: ServiceId?,
val pni: PNI?, val pni: PNI?,
val username: String?, val username: String?,
val e164: String?, val e164: String?,

View file

@ -9,6 +9,7 @@ import androidx.annotation.WorkerThread;
import org.signal.core.util.ThreadUtil; import org.signal.core.util.ThreadUtil;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Collection; import java.util.Collection;
@ -28,14 +29,14 @@ public final class UpdateDescription {
String create(); String create();
} }
private final Collection<ACI> mentioned; private final Collection<ServiceId> mentioned;
private final StringFactory stringFactory; private final StringFactory stringFactory;
private final String staticString; private final String staticString;
private final int lightIconResource; private final int lightIconResource;
private final int lightTint; private final int lightTint;
private final int darkTint; private final int darkTint;
private UpdateDescription(@NonNull Collection<ACI> mentioned, private UpdateDescription(@NonNull Collection<ServiceId> mentioned,
@Nullable StringFactory stringFactory, @Nullable StringFactory stringFactory,
@Nullable String staticString, @Nullable String staticString,
@DrawableRes int iconResource, @DrawableRes int iconResource,
@ -60,11 +61,11 @@ public final class UpdateDescription {
* @param mentioned UUIDs of recipients that are mentioned in the string. * @param mentioned UUIDs of recipients that are mentioned in the string.
* @param stringFactory The background method for generating the string. * @param stringFactory The background method for generating the string.
*/ */
public static UpdateDescription mentioning(@NonNull Collection<ACI> mentioned, public static UpdateDescription mentioning(@NonNull Collection<ServiceId> mentioned,
@NonNull StringFactory stringFactory, @NonNull StringFactory stringFactory,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
return new UpdateDescription(ACI.filterKnown(mentioned), return new UpdateDescription(ServiceId.filterKnown(mentioned),
stringFactory, stringFactory,
null, null,
iconResource, iconResource,
@ -118,7 +119,7 @@ public final class UpdateDescription {
} }
@AnyThread @AnyThread
public Collection<ACI> getMentioned() { public Collection<ServiceId> getMentioned() {
return mentioned; return mentioned;
} }
@ -149,7 +150,7 @@ public final class UpdateDescription {
); );
} }
Set<ACI> allMentioned = new HashSet<>(); Set<ServiceId> allMentioned = new HashSet<>();
for (UpdateDescription updateDescription : updateDescriptions) { for (UpdateDescription updateDescription : updateDescriptions) {
allMentioned.addAll(updateDescription.getMentioned()); allMentioned.addAll(updateDescription.getMentioned());

View file

@ -104,7 +104,7 @@ final class GroupManagerV2 {
this.groupsV2Operations = ApplicationDependencies.getGroupsV2Operations(); this.groupsV2Operations = ApplicationDependencies.getGroupsV2Operations();
this.authorization = ApplicationDependencies.getGroupsV2Authorization(); this.authorization = ApplicationDependencies.getGroupsV2Authorization();
this.groupsV2StateProcessor = ApplicationDependencies.getGroupsV2StateProcessor(); this.groupsV2StateProcessor = ApplicationDependencies.getGroupsV2StateProcessor();
this.selfAci = Recipient.self().requireAci(); this.selfAci = SignalStore.account().requireAci();
this.groupCandidateHelper = new GroupCandidateHelper(context); this.groupCandidateHelper = new GroupCandidateHelper(context);
} }
@ -142,7 +142,7 @@ final class GroupManagerV2 {
Map<UUID, UuidCiphertext> uuidCipherTexts = new HashMap<>(); Map<UUID, UuidCiphertext> uuidCipherTexts = new HashMap<>();
for (Recipient recipient : recipients) { for (Recipient recipient : recipients) {
uuidCipherTexts.put(recipient.requireAci().uuid(), clientZkGroupCipher.encryptUuid(recipient.requireAci().uuid())); uuidCipherTexts.put(recipient.requireServiceId().uuid(), clientZkGroupCipher.encryptUuid(recipient.requireServiceId().uuid()));
} }
return uuidCipherTexts; return uuidCipherTexts;
@ -389,7 +389,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{ {
Set<UUID> uuids = Stream.of(recipientIds) Set<UUID> uuids = Stream.of(recipientIds)
.map(r -> Recipient.resolved(r).requireAci().uuid()) .map(r -> Recipient.resolved(r).requireServiceId().uuid())
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return commitChangeWithConflictResolution(groupOperations.createApproveGroupJoinRequest(uuids)); return commitChangeWithConflictResolution(groupOperations.createApproveGroupJoinRequest(uuids));
@ -400,7 +400,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{ {
Set<UUID> uuids = Stream.of(recipientIds) Set<UUID> uuids = Stream.of(recipientIds)
.map(r -> Recipient.resolved(r).requireAci().uuid()) .map(r -> Recipient.resolved(r).requireServiceId().uuid())
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return commitChangeWithConflictResolution(groupOperations.createRefuseGroupJoinRequest(uuids)); return commitChangeWithConflictResolution(groupOperations.createRefuseGroupJoinRequest(uuids));
@ -412,7 +412,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{ {
Recipient recipient = Recipient.resolved(recipientId); Recipient recipient = Recipient.resolved(recipientId);
return commitChangeWithConflictResolution(groupOperations.createChangeMemberRole(recipient.requireAci().uuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT)); return commitChangeWithConflictResolution(groupOperations.createChangeMemberRole(recipient.requireServiceId().uuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
} }
@WorkerThread @WorkerThread
@ -441,7 +441,7 @@ final class GroupManagerV2 {
{ {
Recipient recipient = Recipient.resolved(recipientId); Recipient recipient = Recipient.resolved(recipientId);
return commitChangeWithConflictResolution(groupOperations.createRemoveMembersChange(Collections.singleton(recipient.requireAci().uuid()))); return commitChangeWithConflictResolution(groupOperations.createRemoveMembersChange(Collections.singleton(recipient.requireServiceId().uuid())));
} }
@WorkerThread @WorkerThread
@ -449,7 +449,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException
{ {
Recipient self = Recipient.self(); Recipient self = Recipient.self();
List<UUID> newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).requireAci().uuid()).toList(); List<UUID> newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).requireServiceId().uuid()).toList();
return commitChangeWithConflictResolution(groupOperations.createLeaveAndPromoteMembersToAdmin(selfAci.uuid(), return commitChangeWithConflictResolution(groupOperations.createLeaveAndPromoteMembersToAdmin(selfAci.uuid(),
newAdminRecipients)); newAdminRecipients));

View file

@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.groupsv2.PartialDecryptedGroup; import org.whispersystems.signalservice.api.groupsv2.PartialDecryptedGroup;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
@ -85,24 +86,24 @@ public final class GroupProtoUtil {
@WorkerThread @WorkerThread
public static Recipient uuidByteStringToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) { public static Recipient uuidByteStringToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) {
ACI aci = ACI.fromByteString(uuidByteString); ServiceId serviceId = ACI.fromByteString(uuidByteString);
if (aci.isUnknown()) { if (serviceId.isUnknown()) {
return Recipient.UNKNOWN; return Recipient.UNKNOWN;
} }
return Recipient.externalPush(context, aci, null, false); return Recipient.externalPush(serviceId, null, false);
} }
@WorkerThread @WorkerThread
public static @NonNull RecipientId uuidByteStringToRecipientId(@NonNull ByteString uuidByteString) { public static @NonNull RecipientId uuidByteStringToRecipientId(@NonNull ByteString uuidByteString) {
ACI aci = ACI.fromByteString(uuidByteString); ServiceId serviceId = ACI.fromByteString(uuidByteString);
if (aci.isUnknown()) { if (serviceId.isUnknown()) {
return RecipientId.UNKNOWN; return RecipientId.UNKNOWN;
} }
return RecipientId.from(aci, null); return RecipientId.from(serviceId, null);
} }
public static boolean isMember(@NonNull UUID uuid, @NonNull List<DecryptedMember> membersList) { public static boolean isMember(@NonNull UUID uuid, @NonNull List<DecryptedMember> membersList) {

View file

@ -99,7 +99,7 @@ public final class GroupV1MessageProcessor {
if (group.getMembers().isPresent()) { if (group.getMembers().isPresent()) {
for (SignalServiceAddress member : group.getMembers().get()) { for (SignalServiceAddress member : group.getMembers().get()) {
members.add(Recipient.externalGV1Member(context, member).getId()); members.add(Recipient.externalGV1Member(member).getId());
} }
} }
@ -131,7 +131,7 @@ public final class GroupV1MessageProcessor {
if (group.getMembers().isPresent()) { if (group.getMembers().isPresent()) {
for (SignalServiceAddress messageMember : group.getMembers().get()) { for (SignalServiceAddress messageMember : group.getMembers().get()) {
messageMembers.add(Recipient.externalGV1Member(context, messageMember).getId()); messageMembers.add(Recipient.externalGV1Member(messageMember).getId());
} }
} }

View file

@ -232,7 +232,7 @@ public final class GroupsV1MigrationUtil {
* True if the user meets all the requirements to be auto-migrated, otherwise false. * True if the user meets all the requirements to be auto-migrated, otherwise false.
*/ */
public static boolean isAutoMigratable(@NonNull Recipient recipient) { public static boolean isAutoMigratable(@NonNull Recipient recipient) {
return recipient.hasAci() && return recipient.hasServiceId() &&
recipient.getGroupsV2Capability() == Recipient.Capability.SUPPORTED && recipient.getGroupsV2Capability() == Recipient.Capability.SUPPORTED &&
recipient.getGroupsV1MigrationCapability() == Recipient.Capability.SUPPORTED && recipient.getGroupsV1MigrationCapability() == Recipient.Capability.SUPPORTED &&
recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED && recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED &&

View file

@ -91,7 +91,7 @@ public final class GroupsV2CapabilityChecker {
} }
} }
if (!member.hasAci()) { if (!member.hasServiceId()) {
noUuidCount++; noUuidCount++;
} }
} }

View file

@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Collections; import java.util.Collections;
@ -109,7 +110,7 @@ public final class LiveGroup {
return Stream.of(requestingMembersList) return Stream.of(requestingMembersList)
.map(requestingMember -> { .map(requestingMember -> {
Recipient recipient = Recipient.externalPush(ApplicationDependencies.getApplication(), ACI.fromByteString(requestingMember.getUuid()), null, false); Recipient recipient = Recipient.externalPush(ServiceId.fromByteString(requestingMember.getUuid()), null, false);
return new GroupMemberEntry.RequestingMember(recipient, selfAdmin); return new GroupMemberEntry.RequestingMember(recipient, selfAdmin);
}) })
.toList(); .toList();

View file

@ -54,7 +54,7 @@ final class PendingMemberInvitesRepository {
List<DecryptedPendingMember> pendingMembersList = decryptedGroup.getPendingMembersList(); List<DecryptedPendingMember> pendingMembersList = decryptedGroup.getPendingMembersList();
List<SinglePendingMemberInvitedByYou> byMe = new ArrayList<>(pendingMembersList.size()); List<SinglePendingMemberInvitedByYou> byMe = new ArrayList<>(pendingMembersList.size());
List<MultiplePendingMembersInvitedByAnother> byOthers = new ArrayList<>(pendingMembersList.size()); List<MultiplePendingMembersInvitedByAnother> byOthers = new ArrayList<>(pendingMembersList.size());
ByteString self = Recipient.self().requireAci().toByteString(); ByteString self = Recipient.self().requireServiceId().toByteString();
boolean selfIsAdmin = v2GroupProperties.isAdmin(Recipient.self()); boolean selfIsAdmin = v2GroupProperties.isAdmin(Recipient.self());
Stream.of(pendingMembersList) Stream.of(pendingMembersList)

View file

@ -95,7 +95,7 @@ final class GroupsV1MigrationRepository {
group = group.fresh(); group = group.fresh();
List<Recipient> ineligible = Stream.of(group.getParticipants()) List<Recipient> ineligible = Stream.of(group.getParticipants())
.filter(r -> !r.hasAci() || .filter(r -> !r.hasServiceId() ||
r.getGroupsV2Capability() != Recipient.Capability.SUPPORTED || r.getGroupsV2Capability() != Recipient.Capability.SUPPORTED ||
r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED || r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED ||
r.getRegistered() != RecipientDatabase.RegisteredState.REGISTERED) r.getRegistered() != RecipientDatabase.RegisteredState.REGISTERED)

View file

@ -18,6 +18,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.groupsv2.GroupCandidate; import org.whispersystems.signalservice.api.groupsv2.GroupCandidate;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@ -47,13 +48,13 @@ public final class GroupCandidateHelper {
{ {
final Recipient recipient = Recipient.resolved(recipientId); final Recipient recipient = Recipient.resolved(recipientId);
ACI aci = recipient.getAci().orNull(); ServiceId serviceId = recipient.getServiceId().orNull();
if (aci == null) { if (serviceId == null) {
throw new AssertionError("Non UUID members should have need detected by now"); throw new AssertionError("Non UUID members should have need detected by now");
} }
Optional<ProfileKeyCredential> profileKeyCredential = Optional.fromNullable(recipient.getProfileKeyCredential()); Optional<ProfileKeyCredential> profileKeyCredential = Optional.fromNullable(recipient.getProfileKeyCredential());
GroupCandidate candidate = new GroupCandidate(aci.uuid(), profileKeyCredential); GroupCandidate candidate = new GroupCandidate(serviceId.uuid(), profileKeyCredential);
if (!candidate.hasProfileKeyCredential()) { if (!candidate.hasProfileKeyCredential()) {
ProfileKey profileKey = ProfileKeyUtil.profileKeyOrNull(recipient.getProfileKey()); ProfileKey profileKey = ProfileKeyUtil.profileKeyOrNull(recipient.getProfileKey());
@ -61,7 +62,7 @@ public final class GroupCandidateHelper {
if (profileKey != null) { if (profileKey != null) {
Log.i(TAG, String.format("No profile key credential on recipient %s, fetching", recipient.getId())); Log.i(TAG, String.format("No profile key credential on recipient %s, fetching", recipient.getId()));
Optional<ProfileKeyCredential> profileKeyCredentialOptional = signalServiceAccountManager.resolveProfileKeyCredential(aci, profileKey, Locale.getDefault()); Optional<ProfileKeyCredential> profileKeyCredentialOptional = signalServiceAccountManager.resolveProfileKeyCredential(serviceId, profileKey, Locale.getDefault());
if (profileKeyCredentialOptional.isPresent()) { if (profileKeyCredentialOptional.isPresent()) {
boolean updatedProfileKey = recipientDatabase.setProfileKeyCredential(recipient.getId(), profileKey, profileKeyCredentialOptional.get()); boolean updatedProfileKey = recipientDatabase.setProfileKeyCredential(recipient.getId(), profileKey, profileKeyCredentialOptional.get());

View file

@ -103,7 +103,7 @@ public final class GroupsV2StateProcessor {
} }
public StateProcessorForGroup forGroup(@NonNull GroupMasterKey groupMasterKey) { public StateProcessorForGroup forGroup(@NonNull GroupMasterKey groupMasterKey) {
ACI selfAci = Recipient.self().requireAci(); ACI selfAci = SignalStore.account().requireAci();
ProfileAndMessageHelper profileAndMessageHelper = new ProfileAndMessageHelper(context, selfAci, groupMasterKey, GroupId.v2(groupMasterKey), recipientDatabase); ProfileAndMessageHelper profileAndMessageHelper = new ProfileAndMessageHelper(context, selfAci, groupMasterKey, GroupId.v2(groupMasterKey), recipientDatabase);
return new StateProcessorForGroup(selfAci, context, groupDatabase, groupsV2Api, groupsV2Authorization, groupMasterKey, profileAndMessageHelper); return new StateProcessorForGroup(selfAci, context, groupDatabase, groupsV2Api, groupsV2Authorization, groupMasterKey, profileAndMessageHelper);
@ -546,14 +546,14 @@ public final class GroupsV2StateProcessor {
static class ProfileAndMessageHelper { static class ProfileAndMessageHelper {
private final Context context; private final Context context;
private final ACI aci; private final ACI selfAci;
private final GroupMasterKey masterKey; private final GroupMasterKey masterKey;
private final GroupId.V2 groupId; private final GroupId.V2 groupId;
private final RecipientDatabase recipientDatabase; private final RecipientDatabase recipientDatabase;
ProfileAndMessageHelper(@NonNull Context context, @NonNull ACI aci, @NonNull GroupMasterKey masterKey, @NonNull GroupId.V2 groupId, @NonNull RecipientDatabase recipientDatabase) { ProfileAndMessageHelper(@NonNull Context context, @NonNull ACI selfAci, @NonNull GroupMasterKey masterKey, @NonNull GroupId.V2 groupId, @NonNull RecipientDatabase recipientDatabase) {
this.context = context; this.context = context;
this.aci = aci; this.selfAci = selfAci;
this.masterKey = masterKey; this.masterKey = masterKey;
this.groupId = groupId; this.groupId = groupId;
this.recipientDatabase = recipientDatabase; this.recipientDatabase = recipientDatabase;
@ -561,14 +561,14 @@ public final class GroupsV2StateProcessor {
void determineProfileSharing(@NonNull GlobalGroupState inputGroupState, @NonNull DecryptedGroup newLocalState) { void determineProfileSharing(@NonNull GlobalGroupState inputGroupState, @NonNull DecryptedGroup newLocalState) {
if (inputGroupState.getLocalState() != null) { if (inputGroupState.getLocalState() != null) {
boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), aci.uuid()).isPresent(); boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), selfAci.uuid()).isPresent();
if (wasAMemberAlready) { if (wasAMemberAlready) {
return; return;
} }
} }
Optional<DecryptedMember> selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), aci.uuid()); Optional<DecryptedMember> selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), selfAci.uuid());
if (selfAsMemberOptional.isPresent()) { if (selfAsMemberOptional.isPresent()) {
DecryptedMember selfAsMember = selfAsMemberOptional.get(); DecryptedMember selfAsMember = selfAsMemberOptional.get();
@ -579,7 +579,7 @@ public final class GroupsV2StateProcessor {
.filter(c -> c != null && c.getRevision() == revisionJoinedAt) .filter(c -> c != null && c.getRevision() == revisionJoinedAt)
.findFirst() .findFirst()
.map(c -> Optional.fromNullable(UuidUtil.fromByteStringOrNull(c.getEditor())) .map(c -> Optional.fromNullable(UuidUtil.fromByteStringOrNull(c.getEditor()))
.transform(a -> Recipient.externalPush(context, ACI.fromByteStringOrNull(c.getEditor()), null, false))) .transform(a -> Recipient.externalPush(ACI.fromByteStringOrNull(c.getEditor()), null, false)))
.orElse(Optional.absent()); .orElse(Optional.absent());
if (addedByOptional.isPresent()) { if (addedByOptional.isPresent()) {
@ -652,7 +652,7 @@ public final class GroupsV2StateProcessor {
void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp) { void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp) {
Optional<ACI> editor = getEditor(decryptedGroupV2Context).transform(ACI::from); Optional<ACI> editor = getEditor(decryptedGroupV2Context).transform(ACI::from);
boolean outgoing = !editor.isPresent() || aci.equals(editor.get()); boolean outgoing = !editor.isPresent() || selfAci.equals(editor.get());
if (outgoing) { if (outgoing) {
try { try {
@ -690,7 +690,7 @@ public final class GroupsV2StateProcessor {
if (changeEditor.isPresent()) { if (changeEditor.isPresent()) {
return changeEditor; return changeEditor;
} else { } else {
Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), aci.uuid()); Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), selfAci.uuid());
if (pendingByUuid.isPresent()) { if (pendingByUuid.isPresent()) {
return Optional.fromNullable(UuidUtil.fromByteStringOrNull(pendingByUuid.get().getAddedByUuid())); return Optional.fromNullable(UuidUtil.fromByteStringOrNull(pendingByUuid.get().getAddedByUuid()));
} }

View file

@ -14,7 +14,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.whispersystems.libsignal.state.SignalProtocolStore; import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.IOException; import java.io.IOException;
@ -70,27 +71,27 @@ public class CreateSignedPreKeyJob extends BaseJob {
return; return;
} }
createPreKeys(SignalStore.account().getAci(), ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys()); createPreKeys(ServiceIdType.ACI, SignalStore.account().getAci(), ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys());
createPreKeys(SignalStore.account().getPni(), ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys()); createPreKeys(ServiceIdType.PNI, SignalStore.account().getPni(), ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys());
} }
private void createPreKeys(@Nullable AccountIdentifier accountId, @NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) private void createPreKeys(@NonNull ServiceIdType serviceIdType, @Nullable ServiceId serviceId, @NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore)
throws IOException throws IOException
{ {
if (accountId == null) { if (serviceId == null) {
warn(TAG, "AccountId not set!"); warn(TAG, "AccountId not set!");
return; return;
} }
if (metadataStore.isSignedPreKeyRegistered()) { if (metadataStore.isSignedPreKeyRegistered()) {
warn(TAG, "Signed prekey for " + (accountId.isAci() ? "ACI" : "PNI") + " already registered..."); warn(TAG, "Signed prekey for " + serviceIdType + " already registered...");
return; return;
} }
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager(); SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, true); SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, true);
accountManager.setSignedPreKey(accountId, signedPreKeyRecord); accountManager.setSignedPreKey(serviceIdType, signedPreKeyRecord);
metadataStore.setSignedPreKeyRegistered(true); metadataStore.setSignedPreKeyRegistered(true);
} }

View file

@ -82,7 +82,7 @@ public class MultiDeviceBlockedUpdateJob extends BaseJob {
while ((recipient = reader.getNext()) != null) { while ((recipient = reader.getNext()) != null) {
if (recipient.isPushGroup()) { if (recipient.isPushGroup()) {
blockedGroups.add(recipient.requireGroupId().getDecodedId()); blockedGroups.add(recipient.requireGroupId().getDecodedId());
} else if (recipient.isMaybeRegistered() && (recipient.hasAci() || recipient.hasE164())) { } else if (recipient.isMaybeRegistered() && (recipient.hasServiceId() || recipient.hasE164())) {
blockedIndividuals.add(RecipientUtil.toSignalServiceAddress(context, recipient)); blockedIndividuals.add(RecipientUtil.toSignalServiceAddress(context, recipient));
} }
} }

View file

@ -75,7 +75,7 @@ class MultiDeviceContactSyncJob(parameters: Parameters, private val attachmentPo
var contact: DeviceContact? = deviceContacts.read() var contact: DeviceContact? = deviceContacts.read()
while (contact != null) { while (contact != null) {
val recipient = Recipient.externalPush(context, contact.address.aci, contact.address.number.orNull(), true) val recipient = Recipient.externalPush(contact.address.serviceId, contact.address.number.orNull(), true)
if (recipient.isSelf) { if (recipient.isSelf) {
contact = deviceContacts.read() contact = deviceContacts.read()

View file

@ -101,8 +101,8 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob {
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender(); SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
Recipient recipient = Recipient.resolved(threadRecipient); Recipient recipient = Recipient.resolved(threadRecipient);
if (!recipient.hasServiceIdentifier()) { if (!recipient.hasServiceId()) {
Log.i(TAG, "Queued for recipient without service identifier"); Log.i(TAG, "Queued for recipient without ServiceId");
return; return;
} }

View file

@ -91,7 +91,7 @@ public final class MultiDeviceOutgoingPaymentSyncJob extends BaseJob {
Optional<SignalServiceAddress> uuid; Optional<SignalServiceAddress> uuid;
if (!defrag && payment.getPayee().hasRecipientId()) { if (!defrag && payment.getPayee().hasRecipientId()) {
uuid = Optional.of(new SignalServiceAddress(Recipient.resolved(payment.getPayee().requireRecipientId()).requireAci())); uuid = Optional.of(new SignalServiceAddress(Recipient.resolved(payment.getPayee().requireRecipientId()).requireServiceId()));
} else { } else {
uuid = Optional.absent(); uuid = Optional.absent();
} }

View file

@ -74,8 +74,8 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
Set<RecipientId> recipients = Stream.concat(Stream.of(memberUuids), Stream.of(pendingUuids)) Set<RecipientId> recipients = Stream.concat(Stream.of(memberUuids), Stream.of(pendingUuids))
.filter(uuid -> !UuidUtil.UNKNOWN_UUID.equals(uuid)) .filter(uuid -> !UuidUtil.UNKNOWN_UUID.equals(uuid))
.filter(uuid -> !Recipient.self().requireAci().uuid().equals(uuid)) .filter(uuid -> !Recipient.self().requireServiceId().uuid().equals(uuid))
.map(uuid -> Recipient.externalPush(context, ACI.from(uuid), null, false)) .map(uuid -> Recipient.externalPush(ACI.from(uuid), null, false))
.filter(recipient -> recipient.getRegistered() != RecipientDatabase.RegisteredState.NOT_REGISTERED) .filter(recipient -> recipient.getRegistered() != RecipientDatabase.RegisteredState.NOT_REGISTERED)
.map(Recipient::getId) .map(Recipient::getId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());

View file

@ -41,7 +41,6 @@ import org.whispersystems.signalservice.api.messages.SendMessageResult;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException;
@ -75,8 +74,8 @@ public class PushMediaSendJob extends PushSendJob {
@WorkerThread @WorkerThread
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Recipient recipient) { public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Recipient recipient) {
try { try {
if (!recipient.hasServiceIdentifier()) { if (!recipient.hasServiceId()) {
throw new AssertionError(); throw new AssertionError("No ServiceId!");
} }
MessageDatabase database = SignalDatabase.mms(); MessageDatabase database = SignalDatabase.mms();
@ -226,7 +225,7 @@ public class PushMediaSendJob extends PushSendJob {
.asExpirationUpdate(message.isExpirationUpdate()) .asExpirationUpdate(message.isExpirationUpdate())
.build(); .build();
if (Util.equals(SignalStore.account().getAci(), address.getAci())) { if (Util.equals(SignalStore.account().getAci(), address.getServiceId())) {
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
SendMessageResult result = messageSender.sendSyncMessage(mediaMessage); SendMessageResult result = messageSender.sendSyncMessage(mediaMessage);
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true)); SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true));

View file

@ -49,17 +49,13 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.Hex; import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview;
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
@ -70,7 +66,6 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -409,7 +404,7 @@ public abstract class PushSendJob extends SendJob {
List<SignalServiceDataMessage.Mention> getMentionsFor(@NonNull List<Mention> mentions) { List<SignalServiceDataMessage.Mention> getMentionsFor(@NonNull List<Mention> mentions) {
return Stream.of(mentions) return Stream.of(mentions)
.map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireAci(), m.getStart(), m.getLength())) .map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireServiceId(), m.getStart(), m.getLength()))
.toList(); .toList();
} }

View file

@ -31,7 +31,6 @@ import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.SendMessageResult; import org.whispersystems.signalservice.api.messages.SendMessageResult;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
@ -188,7 +187,7 @@ public class PushTextSendJob extends PushSendJob {
.asEndSessionMessage(message.isEndSession()) .asEndSessionMessage(message.isEndSession())
.build(); .build();
if (Util.equals(SignalStore.account().getAci(), address.getAci())) { if (Util.equals(SignalStore.account().getAci(), address.getServiceId())) {
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId); SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId);

View file

@ -17,8 +17,9 @@ import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
@ -81,19 +82,17 @@ public class RefreshPreKeysJob extends BaseJob {
return; return;
} }
ACI aci = SignalStore.account().getAci();
SignalProtocolStore aciProtocolStore = ApplicationDependencies.getProtocolStore().aci(); SignalProtocolStore aciProtocolStore = ApplicationDependencies.getProtocolStore().aci();
PreKeyMetadataStore aciPreKeyStore = SignalStore.account().aciPreKeys(); PreKeyMetadataStore aciPreKeyStore = SignalStore.account().aciPreKeys();
PNI pni = SignalStore.account().getPni();
SignalProtocolStore pniProtocolStore = ApplicationDependencies.getProtocolStore().pni(); SignalProtocolStore pniProtocolStore = ApplicationDependencies.getProtocolStore().pni();
PreKeyMetadataStore pniPreKeyStore = SignalStore.account().pniPreKeys(); PreKeyMetadataStore pniPreKeyStore = SignalStore.account().pniPreKeys();
if (refreshKeys(aci, aciProtocolStore, aciPreKeyStore)) { if (refreshKeys(ServiceIdType.ACI, aciProtocolStore, aciPreKeyStore)) {
PreKeyUtil.cleanSignedPreKeys(aciProtocolStore, aciPreKeyStore); PreKeyUtil.cleanSignedPreKeys(aciProtocolStore, aciPreKeyStore);
} }
if (refreshKeys(pni, pniProtocolStore, pniPreKeyStore)) { if (refreshKeys(ServiceIdType.PNI, pniProtocolStore, pniPreKeyStore)) {
PreKeyUtil.cleanSignedPreKeys(pniProtocolStore, pniPreKeyStore); PreKeyUtil.cleanSignedPreKeys(pniProtocolStore, pniPreKeyStore);
} }
@ -104,16 +103,12 @@ public class RefreshPreKeysJob extends BaseJob {
/** /**
* @return True if we need to clean prekeys, otherwise false. * @return True if we need to clean prekeys, otherwise false.
*/ */
private boolean refreshKeys(@Nullable AccountIdentifier accountId, @NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) throws IOException { private boolean refreshKeys(@NonNull ServiceIdType serviceIdType, @NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) throws IOException {
if (accountId == null) { String logPrefix = "[" + serviceIdType + "] ";
throw new IOException("Unset identifier!");
}
String logPrefix = "[" + (accountId.isAci() ? "ACI" : "PNI") + "] ";
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager(); SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
int availableKeys = accountManager.getPreKeysCount(accountId); int availableKeys = accountManager.getPreKeysCount(serviceIdType);
log(TAG, logPrefix + "Available keys: " + availableKeys); log(TAG, logPrefix + "Available keys: " + availableKeys);
if (availableKeys >= PREKEY_MINIMUM && metadataStore.isSignedPreKeyRegistered()) { if (availableKeys >= PREKEY_MINIMUM && metadataStore.isSignedPreKeyRegistered()) {
@ -127,7 +122,7 @@ public class RefreshPreKeysJob extends BaseJob {
log(TAG, logPrefix + "Registering new prekeys..."); log(TAG, logPrefix + "Registering new prekeys...");
accountManager.setPreKeys(accountId, identityKey.getPublicKey(), signedPreKeyRecord, preKeyRecords); accountManager.setPreKeys(serviceIdType, identityKey.getPublicKey(), signedPreKeyRecord, preKeyRecords);
metadataStore.setActiveSignedPreKeyId(signedPreKeyRecord.getId()); metadataStore.setActiveSignedPreKeyId(signedPreKeyRecord.getId());
metadataStore.setSignedPreKeyRegistered(true); metadataStore.setSignedPreKeyRegistered(true);

View file

@ -158,7 +158,7 @@ public class ResendMessageJob extends BaseJob {
List<SignalProtocolAddress> addresses = result.getSuccess() List<SignalProtocolAddress> addresses = result.getSuccess()
.getDevices() .getDevices()
.stream() .stream()
.map(device -> new SignalProtocolAddress(recipient.requireServiceId(), device)) .map(device -> recipient.requireServiceId().toProtocolAddress(device))
.collect(Collectors.toList()); .collect(Collectors.toList());
ApplicationDependencies.getProtocolStore().aci().markSenderKeySharedWith(distributionId, addresses); ApplicationDependencies.getProtocolStore().aci().markSenderKeySharedWith(distributionId, addresses);

View file

@ -47,7 +47,7 @@ import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
import org.whispersystems.signalservice.api.crypto.ProfileCipher; import org.whispersystems.signalservice.api.crypto.ProfileCipher;
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential; import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.services.ProfileService; import org.whispersystems.signalservice.api.services.ProfileService;
import org.whispersystems.signalservice.internal.ServiceResponse; import org.whispersystems.signalservice.internal.ServiceResponse;
@ -257,7 +257,7 @@ public class RetrieveProfileJob extends BaseJob {
ApplicationDependencies.getSignalWebSocket()); ApplicationDependencies.getSignalWebSocket());
List<Observable<Pair<Recipient, ServiceResponse<ProfileAndCredential>>>> requests = Stream.of(recipients) List<Observable<Pair<Recipient, ServiceResponse<ProfileAndCredential>>>> requests = Stream.of(recipients)
.filter(Recipient::hasServiceIdentifier) .filter(Recipient::hasServiceId)
.map(r -> ProfileUtil.retrieveProfile(context, r, getRequestType(r), profileService).toObservable()) .map(r -> ProfileUtil.retrieveProfile(context, r, getRequestType(r), profileService).toObservable())
.toList(); .toList();
stopwatch.split("requests"); stopwatch.split("requests");
@ -288,11 +288,11 @@ public class RetrieveProfileJob extends BaseJob {
Set<RecipientId> success = SetUtil.difference(recipientIds, operationState.retries); Set<RecipientId> success = SetUtil.difference(recipientIds, operationState.retries);
Map<RecipientId, ACI> newlyRegistered = Stream.of(operationState.profiles) Map<RecipientId, ServiceId> newlyRegistered = Stream.of(operationState.profiles)
.map(Pair::first) .map(Pair::first)
.filterNot(Recipient::isRegistered) .filterNot(Recipient::isRegistered)
.collect(Collectors.toMap(Recipient::getId, .collect(Collectors.toMap(Recipient::getId,
r -> r.getAci().orNull())); r -> r.getServiceId().orNull()));
//noinspection SimplifyStreamApiCallChains //noinspection SimplifyStreamApiCallChains
@ -401,7 +401,7 @@ public class RetrieveProfileJob extends BaseJob {
return; return;
} }
IdentityUtil.saveIdentity(recipient.requireServiceId(), identityKey); IdentityUtil.saveIdentity(recipient.requireServiceId().toString(), identityKey);
} catch (InvalidKeyException | IOException e) { } catch (InvalidKeyException | IOException e) {
Log.w(TAG, e); Log.w(TAG, e);
} }

View file

@ -11,13 +11,13 @@ import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.state.SignalProtocolStore; import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.IOException; import java.io.IOException;
@ -73,17 +73,17 @@ public class RotateSignedPreKeyJob extends BaseJob {
return; return;
} }
rotate(aci, ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys()); rotate(ServiceIdType.ACI, ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys());
rotate(pni, ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys()); rotate(ServiceIdType.PNI, ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys());
} }
private void rotate(@NonNull AccountIdentifier accountId, @NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) private void rotate(@NonNull ServiceIdType serviceIdType, @NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore)
throws IOException throws IOException
{ {
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager(); SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, false); SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, false);
accountManager.setSignedPreKey(accountId, signedPreKeyRecord); accountManager.setSignedPreKey(serviceIdType, signedPreKeyRecord);
metadataStore.setActiveSignedPreKeyId(signedPreKeyRecord.getId()); metadataStore.setActiveSignedPreKeyId(signedPreKeyRecord.getId());
metadataStore.setSignedPreKeyRegistered(true); metadataStore.setSignedPreKeyRegistered(true);

View file

@ -107,7 +107,7 @@ public final class SenderKeyDistributionSendJob extends BaseJob {
List<SignalProtocolAddress> addresses = result.getSuccess() List<SignalProtocolAddress> addresses = result.getSuccess()
.getDevices() .getDevices()
.stream() .stream()
.map(device -> new SignalProtocolAddress(recipient.requireServiceId(), device)) .map(device -> recipient.requireServiceId().toProtocolAddress(device))
.collect(Collectors.toList()); .collect(Collectors.toList());
ApplicationDependencies.getProtocolStore().aci().markSenderKeySharedWith(distributionId, addresses); ApplicationDependencies.getProtocolStore().aci().markSenderKeySharedWith(distributionId, addresses);

View file

@ -176,7 +176,7 @@ public class StorageSyncJob extends BaseJob {
return; return;
} }
if (!Recipient.self().hasE164() || !Recipient.self().hasAci()) { if (!Recipient.self().hasE164() || !Recipient.self().hasServiceId()) {
Log.w(TAG, "Missing E164 or ACI!"); Log.w(TAG, "Missing E164 or ACI!");
return; return;
} }

View file

@ -88,6 +88,11 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
val aci: ACI? val aci: ACI?
get() = ACI.parseOrNull(getString(KEY_ACI, null)) get() = ACI.parseOrNull(getString(KEY_ACI, null))
/** The local user's [ACI]. Will throw if not present. */
fun requireAci(): ACI {
return ACI.parseOrThrow(getString(KEY_ACI, null))
}
fun setAci(aci: ACI) { fun setAci(aci: ACI) {
putString(KEY_ACI, aci.toString()) putString(KEY_ACI, aci.toString())
} }
@ -96,6 +101,11 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
val pni: PNI? val pni: PNI?
get() = PNI.parseOrNull(getString(KEY_PNI, null)) get() = PNI.parseOrNull(getString(KEY_PNI, null))
/** The local user's [PNI]. Will throw if not present. */
fun requirePni(): PNI {
return PNI.parseOrThrow(getString(KEY_PNI, null))
}
fun setPni(pni: PNI) { fun setPni(pni: PNI) {
putString(KEY_PNI, pni.toString()) putString(KEY_PNI, pni.toString())
} }

View file

@ -42,7 +42,6 @@ import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMess
import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException; import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException; import org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException;
import org.whispersystems.signalservice.internal.push.http.CancelationSignal; import org.whispersystems.signalservice.internal.push.http.CancelationSignal;
import org.whispersystems.signalservice.internal.push.http.PartialSendCompleteListener; import org.whispersystems.signalservice.internal.push.http.PartialSendCompleteListener;
@ -176,7 +175,7 @@ public final class GroupSendUtil {
boolean validMembership = groupRecord.isPresent() && groupRecord.get().getMembers().contains(recipient.getId()); boolean validMembership = groupRecord.isPresent() && groupRecord.get().getMembers().contains(recipient.getId());
if (recipient.getSenderKeyCapability() == Recipient.Capability.SUPPORTED && if (recipient.getSenderKeyCapability() == Recipient.Capability.SUPPORTED &&
recipient.hasAci() && recipient.hasServiceId() &&
access.isPresent() && access.isPresent() &&
access.get().getTargetUnidentifiedAccess().isPresent() && access.get().getTargetUnidentifiedAccess().isPresent() &&
validMembership) validMembership)
@ -311,8 +310,8 @@ public final class GroupSendUtil {
Log.w(TAG, "There are " + unregisteredTargets.size() + " unregistered targets. Including failure results."); Log.w(TAG, "There are " + unregisteredTargets.size() + " unregistered targets. Including failure results.");
List<SendMessageResult> unregisteredResults = unregisteredTargets.stream() List<SendMessageResult> unregisteredResults = unregisteredTargets.stream()
.filter(Recipient::hasAci) .filter(Recipient::hasServiceId)
.map(t -> SendMessageResult.unregisteredFailure(new SignalServiceAddress(t.requireAci(), t.getE164().orNull()))) .map(t -> SendMessageResult.unregisteredFailure(new SignalServiceAddress(t.requireServiceId(), t.getE164().orNull())))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (unregisteredResults.size() < unregisteredTargets.size()) { if (unregisteredResults.size() < unregisteredTargets.size()) {

View file

@ -652,7 +652,7 @@ public final class MessageContentProcessor {
} }
ApplicationDependencies.getSignalCallManager() ApplicationDependencies.getSignalCallManager()
.receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireAci().uuid(), .receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireServiceId().uuid(),
message.getOpaque(), message.getOpaque(),
content.getSenderDevice(), content.getSenderDevice(),
messageAgeSeconds)); messageAgeSeconds));
@ -734,7 +734,7 @@ public final class MessageContentProcessor {
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient); long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
if (!recipient.isGroup()) { if (!recipient.isGroup()) {
ApplicationDependencies.getProtocolStore().aci().deleteAllSessions(recipient.requireServiceId()); ApplicationDependencies.getProtocolStore().aci().deleteAllSessions(recipient.requireServiceId().toString());
SecurityEvent.broadcastSecurityUpdateEvent(context); SecurityEvent.broadcastSecurityUpdateEvent(context);
@ -867,7 +867,7 @@ public final class MessageContentProcessor {
return null; return null;
} }
Recipient targetAuthor = Recipient.externalPush(context, reaction.getTargetAuthor()); Recipient targetAuthor = Recipient.externalPush(reaction.getTargetAuthor());
MessageRecord targetMessage = SignalDatabase.mmsSms().getMessageFor(reaction.getTargetSentTimestamp(), targetAuthor.getId()); MessageRecord targetMessage = SignalDatabase.mmsSms().getMessageFor(reaction.getTargetSentTimestamp(), targetAuthor.getId());
if (targetMessage == null) { if (targetMessage == null) {
@ -1019,7 +1019,7 @@ public final class MessageContentProcessor {
Recipient recipient; Recipient recipient;
if (response.getPerson().isPresent()) { if (response.getPerson().isPresent()) {
recipient = Recipient.externalPush(context, response.getPerson().get()); recipient = Recipient.externalPush(response.getPerson().get());
} else if (response.getGroupId().isPresent()) { } else if (response.getGroupId().isPresent()) {
GroupId groupId = GroupId.v1(response.getGroupId().get()); GroupId groupId = GroupId.v1(response.getGroupId().get());
recipient = Recipient.externalPossiblyMigratedGroup(context, groupId); recipient = Recipient.externalPossiblyMigratedGroup(context, groupId);
@ -1271,7 +1271,7 @@ public final class MessageContentProcessor {
List<Long> toMarkViewed = Stream.of(viewedMessages) List<Long> toMarkViewed = Stream.of(viewedMessages)
.map(message -> { .map(message -> {
RecipientId author = Recipient.externalPush(context, message.getSender()).getId(); RecipientId author = Recipient.externalPush(message.getSender()).getId();
return SignalDatabase.mmsSms().getMessageFor(message.getTimestamp(), author); return SignalDatabase.mmsSms().getMessageFor(message.getTimestamp(), author);
}) })
.filter(message -> message != null && message.isMms()) .filter(message -> message != null && message.isMms())
@ -1289,7 +1289,7 @@ public final class MessageContentProcessor {
private void handleSynchronizeViewOnceOpenMessage(@NonNull ViewOnceOpenMessage openMessage, long envelopeTimestamp) { private void handleSynchronizeViewOnceOpenMessage(@NonNull ViewOnceOpenMessage openMessage, long envelopeTimestamp) {
log(envelopeTimestamp, "Handling a view-once open for message: " + openMessage.getTimestamp()); log(envelopeTimestamp, "Handling a view-once open for message: " + openMessage.getTimestamp());
RecipientId author = Recipient.externalPush(context, openMessage.getSender()).getId(); RecipientId author = Recipient.externalPush(openMessage.getSender()).getId();
long timestamp = openMessage.getTimestamp(); long timestamp = openMessage.getTimestamp();
MessageRecord record = SignalDatabase.mmsSms().getMessageFor(timestamp, author); MessageRecord record = SignalDatabase.mmsSms().getMessageFor(timestamp, author);
@ -1547,7 +1547,7 @@ public final class MessageContentProcessor {
} }
List<org.whispersystems.libsignal.util.Pair<RecipientId, Boolean>> unidentifiedStatus = Stream.of(members) List<org.whispersystems.libsignal.util.Pair<RecipientId, Boolean>> unidentifiedStatus = Stream.of(members)
.map(m -> new org.whispersystems.libsignal.util.Pair<>(m.getId(), message.isUnidentified(m.requireServiceId()))) .map(m -> new org.whispersystems.libsignal.util.Pair<>(m.getId(), message.isUnidentified(m.requireServiceId().toString())))
.toList(); .toList();
receiptDatabase.setUnidentified(unidentifiedStatus, messageId); receiptDatabase.setUnidentified(unidentifiedStatus, messageId);
} }
@ -1913,7 +1913,7 @@ public final class MessageContentProcessor {
warn(content.getTimestamp(), "[RetryReceipt] Received a retry receipt from " + formatSender(senderRecipient, content) + " for message with timestamp " + sentTimestamp + "."); warn(content.getTimestamp(), "[RetryReceipt] Received a retry receipt from " + formatSender(senderRecipient, content) + " for message with timestamp " + sentTimestamp + ".");
if (!senderRecipient.hasAci()) { if (!senderRecipient.hasServiceId()) {
warn(content.getTimestamp(), "[RetryReceipt] Requester " + senderRecipient.getId() + " somehow has no UUID! timestamp: " + sentTimestamp); warn(content.getTimestamp(), "[RetryReceipt] Requester " + senderRecipient.getId() + " somehow has no UUID! timestamp: " + sentTimestamp);
return; return;
} }
@ -1953,7 +1953,7 @@ public final class MessageContentProcessor {
GroupId.V2 groupId = threadRecipient.requireGroupId().requireV2(); GroupId.V2 groupId = threadRecipient.requireGroupId().requireV2();
DistributionId distributionId = SignalDatabase.groups().getOrCreateDistributionId(groupId); DistributionId distributionId = SignalDatabase.groups().getOrCreateDistributionId(groupId);
SignalProtocolAddress requesterAddress = new SignalProtocolAddress(requester.requireAci().toString(), content.getSenderDevice()); SignalProtocolAddress requesterAddress = new SignalProtocolAddress(requester.requireServiceId().toString(), content.getSenderDevice());
SignalDatabase.senderKeyShared().delete(distributionId, Collections.singleton(requesterAddress)); SignalDatabase.senderKeyShared().delete(distributionId, Collections.singleton(requesterAddress));
@ -2030,7 +2030,7 @@ public final class MessageContentProcessor {
} }
public static boolean ratchetKeyMatches(@NonNull Recipient recipient, int deviceId, @NonNull ECPublicKey ratchetKey) { public static boolean ratchetKeyMatches(@NonNull Recipient recipient, int deviceId, @NonNull ECPublicKey ratchetKey) {
SignalProtocolAddress address = new SignalProtocolAddress(recipient.resolve().requireServiceId(), deviceId); SignalProtocolAddress address = recipient.resolve().requireServiceId().toProtocolAddress(deviceId);
SessionRecord session = ApplicationDependencies.getProtocolStore().aci().loadSession(address); SessionRecord session = ApplicationDependencies.getProtocolStore().aci().loadSession(address);
return session.currentRatchetKeyMatches(ratchetKey); return session.currentRatchetKeyMatches(ratchetKey);
@ -2064,7 +2064,7 @@ public final class MessageContentProcessor {
return Optional.absent(); return Optional.absent();
} }
RecipientId author = Recipient.externalPush(context, quote.get().getAuthor()).getId(); RecipientId author = Recipient.externalPush(quote.get().getAuthor()).getId();
MessageRecord message = SignalDatabase.mmsSms().getMessageFor(quote.get().getId(), author); MessageRecord message = SignalDatabase.mmsSms().getMessageFor(quote.get().getId(), author);
if (message != null && !message.isRemoteDelete()) { if (message != null && !message.isRemoteDelete()) {
@ -2200,7 +2200,7 @@ public final class MessageContentProcessor {
List<Mention> mentions = new ArrayList<>(signalServiceMentions.size()); List<Mention> mentions = new ArrayList<>(signalServiceMentions.size());
for (SignalServiceDataMessage.Mention mention : signalServiceMentions) { for (SignalServiceDataMessage.Mention mention : signalServiceMentions) {
mentions.add(new Mention(Recipient.externalPush(context, mention.getAci(), null, false).getId(), mention.getStart(), mention.getLength())); mentions.add(new Mention(Recipient.externalPush(mention.getAci(), null, false).getId(), mention.getStart(), mention.getLength()));
} }
return mentions; return mentions;
@ -2223,7 +2223,7 @@ public final class MessageContentProcessor {
private Recipient getSyncMessageDestination(@NonNull SentTranscriptMessage message) private Recipient getSyncMessageDestination(@NonNull SentTranscriptMessage message)
throws BadGroupIdException throws BadGroupIdException
{ {
return getGroupRecipient(message.getMessage().getGroupContext()).or(() -> Recipient.externalPush(context, message.getDestination().get())); return getGroupRecipient(message.getMessage().getGroupContext()).or(() -> Recipient.externalPush(message.getDestination().get()));
} }
private Recipient getMessageDestination(@NonNull SignalServiceContent content) throws BadGroupIdException { private Recipient getMessageDestination(@NonNull SignalServiceContent content) throws BadGroupIdException {
@ -2339,8 +2339,8 @@ public final class MessageContentProcessor {
if (recipient.hasE164()) { if (recipient.hasE164()) {
unidentified |= message.isUnidentified(recipient.requireE164()); unidentified |= message.isUnidentified(recipient.requireE164());
} }
if (recipient.hasAci()) { if (recipient.hasServiceId()) {
unidentified |= message.isUnidentified(recipient.requireAci()); unidentified |= message.isUnidentified(recipient.requireServiceId());
} }
return unidentified; return unidentified;

View file

@ -44,7 +44,6 @@ import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.GroupUtil;
import org.whispersystems.libsignal.protocol.CiphertextMessage; import org.whispersystems.libsignal.protocol.CiphertextMessage;
import org.whispersystems.libsignal.protocol.DecryptionErrorMessage; import org.whispersystems.libsignal.protocol.DecryptionErrorMessage;
import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.InvalidMessageStructureException; import org.whispersystems.signalservice.api.InvalidMessageStructureException;
import org.whispersystems.signalservice.api.SignalServiceAccountDataStore; import org.whispersystems.signalservice.api.SignalServiceAccountDataStore;
@ -78,7 +77,7 @@ public final class MessageDecryptionUtil {
*/ */
public static @NonNull DecryptionResult decrypt(@NonNull Context context, @NonNull SignalServiceEnvelope envelope) { public static @NonNull DecryptionResult decrypt(@NonNull Context context, @NonNull SignalServiceEnvelope envelope) {
SignalServiceAccountDataStore protocolStore = ApplicationDependencies.getProtocolStore().aci(); SignalServiceAccountDataStore protocolStore = ApplicationDependencies.getProtocolStore().aci();
SignalServiceAddress localAddress = new SignalServiceAddress(Recipient.self().requireAci(), Recipient.self().requireE164()); SignalServiceAddress localAddress = new SignalServiceAddress(Recipient.self().requireServiceId(), Recipient.self().requireE164());
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, SignalStore.account().getDeviceId(), protocolStore, ReentrantSessionLock.INSTANCE, UnidentifiedAccessUtil.getCertificateValidator()); SignalServiceCipher cipher = new SignalServiceCipher(localAddress, SignalStore.account().getDeviceId(), protocolStore, ReentrantSessionLock.INSTANCE, UnidentifiedAccessUtil.getCertificateValidator());
List<Job> jobs = new LinkedList<>(); List<Job> jobs = new LinkedList<>();

View file

@ -17,6 +17,7 @@ import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -71,7 +72,7 @@ public class PniAccountInitializationMigrationJob extends MigrationJob {
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, true); SignedPreKeyRecord signedPreKey = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, true);
List<PreKeyRecord> oneTimePreKeys = PreKeyUtil.generateAndStoreOneTimePreKeys(protocolStore, metadataStore); List<PreKeyRecord> oneTimePreKeys = PreKeyUtil.generateAndStoreOneTimePreKeys(protocolStore, metadataStore);
accountManager.setPreKeys(pni, protocolStore.getIdentityKeyPair().getPublicKey(), signedPreKey, oneTimePreKeys); accountManager.setPreKeys(ServiceIdType.PNI, protocolStore.getIdentityKeyPair().getPublicKey(), signedPreKey, oneTimePreKeys);
metadataStore.setSignedPreKeyRegistered(true); metadataStore.setSignedPreKeyRegistered(true);
} }

View file

@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2; import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2;
@ -191,7 +192,7 @@ public final class MessageGroupContext {
List<RecipientId> members = new ArrayList<>(decryptedGroupV2Context.getGroupState().getMembersCount()); List<RecipientId> members = new ArrayList<>(decryptedGroupV2Context.getGroupState().getMembersCount());
for (DecryptedMember member : decryptedGroupV2Context.getGroupState().getMembersList()) { for (DecryptedMember member : decryptedGroupV2Context.getGroupState().getMembersList()) {
RecipientId recipient = RecipientId.from(ACI.fromByteString(member.getUuid()), null); RecipientId recipient = RecipientId.from(ServiceId.fromByteString(member.getUuid()), null);
if (!Recipient.self().getId().equals(recipient)) { if (!Recipient.self().getId().equals(recipient)) {
members.add(recipient); members.add(recipient);
} }

View file

@ -7,8 +7,6 @@ import android.database.Cursor;
import androidx.annotation.AnyThread; import androidx.annotation.AnyThread;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.signal.core.util.ThreadUtil; import org.signal.core.util.ThreadUtil;
import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
@ -153,7 +151,7 @@ public final class LiveRecipientCache {
String localE164 = SignalStore.account().getE164(); String localE164 = SignalStore.account().getE164();
if (localAci != null) { if (localAci != null) {
selfId = recipientDatabase.getByAci(localAci).or(recipientDatabase.getByE164(localE164)).orNull(); selfId = recipientDatabase.getByServiceId(localAci).or(recipientDatabase.getByE164(localE164)).orNull();
} else if (localE164 != null) { } else if (localE164 != null) {
selfId = recipientDatabase.getByE164(localE164).orNull(); selfId = recipientDatabase.getByE164(localE164).orNull();
} else { } else {
@ -235,6 +233,6 @@ public final class LiveRecipientCache {
} }
private boolean isValidForCache(@NonNull Recipient recipient) { private boolean isValidForCache(@NonNull Recipient recipient) {
return !recipient.getId().isUnknown() && (recipient.hasServiceIdentifier() || recipient.getGroupId().isPresent() || recipient.hasSmsAddress()); return !recipient.getId().isUnknown() && (recipient.hasServiceId() || recipient.getGroupId().isPresent() || recipient.hasSmsAddress());
} }
} }

View file

@ -49,6 +49,7 @@ import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.libsignal.util.guava.Preconditions; import org.whispersystems.libsignal.util.guava.Preconditions;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
@ -78,7 +79,7 @@ public class Recipient {
private final RecipientId id; private final RecipientId id;
private final boolean resolving; private final boolean resolving;
private final ACI aci; private final ServiceId serviceId;
private final PNI pni; private final PNI pni;
private final String username; private final String username;
private final String e164; private final String e164;
@ -166,8 +167,8 @@ public class Recipient {
* Returns a fully-populated {@link Recipient} and associates it with the provided username. * Returns a fully-populated {@link Recipient} and associates it with the provided username.
*/ */
@WorkerThread @WorkerThread
public static @NonNull Recipient externalUsername(@NonNull Context context, @NonNull ACI aci, @NonNull String username) { public static @NonNull Recipient externalUsername(@NonNull ServiceId serviceId, @NonNull String username) {
Recipient recipient = externalPush(context, aci, null, false); Recipient recipient = externalPush(serviceId, null, false);
SignalDatabase.recipients().setUsername(recipient.getId(), username); SignalDatabase.recipients().setUsername(recipient.getId(), username);
return recipient; return recipient;
} }
@ -175,11 +176,11 @@ public class Recipient {
/** /**
* Returns a fully-populated {@link Recipient} based off of a {@link SignalServiceAddress}, * Returns a fully-populated {@link Recipient} based off of a {@link SignalServiceAddress},
* creating one in the database if necessary. Convenience overload of * creating one in the database if necessary. Convenience overload of
* {@link #externalPush(Context, ACI, String, boolean)} * {@link #externalPush(ServiceId, String, boolean)}
*/ */
@WorkerThread @WorkerThread
public static @NonNull Recipient externalPush(@NonNull Context context, @NonNull SignalServiceAddress signalServiceAddress) { public static @NonNull Recipient externalPush(@NonNull SignalServiceAddress signalServiceAddress) {
return externalPush(context, signalServiceAddress.getAci(), signalServiceAddress.getNumber().orNull(), false); return externalPush(signalServiceAddress.getServiceId(), signalServiceAddress.getNumber().orNull(), false);
} }
/** /**
@ -188,11 +189,11 @@ public class Recipient {
* prioritize E164 addresses and not use the UUIDs if possible. * prioritize E164 addresses and not use the UUIDs if possible.
*/ */
@WorkerThread @WorkerThread
public static @NonNull Recipient externalGV1Member(@NonNull Context context, @NonNull SignalServiceAddress address) { public static @NonNull Recipient externalGV1Member(@NonNull SignalServiceAddress address) {
if (address.getNumber().isPresent()) { if (address.getNumber().isPresent()) {
return externalPush(context, null, address.getNumber().get(), false); return externalPush(null, address.getNumber().get(), false);
} else { } else {
return externalPush(context, address.getAci(), null, false); return externalPush(address.getServiceId(), null, false);
} }
} }
@ -207,7 +208,7 @@ public class Recipient {
*/ */
@WorkerThread @WorkerThread
public static @NonNull Recipient externalHighTrustPush(@NonNull Context context, @NonNull SignalServiceAddress signalServiceAddress) { public static @NonNull Recipient externalHighTrustPush(@NonNull Context context, @NonNull SignalServiceAddress signalServiceAddress) {
return externalPush(context, signalServiceAddress.getAci(), signalServiceAddress.getNumber().orNull(), true); return externalPush(signalServiceAddress.getServiceId(), signalServiceAddress.getNumber().orNull(), true);
} }
/** /**
@ -223,13 +224,13 @@ public class Recipient {
* that can be trusted as accurate (like an envelope). * that can be trusted as accurate (like an envelope).
*/ */
@WorkerThread @WorkerThread
public static @NonNull Recipient externalPush(@NonNull Context context, @Nullable ACI aci, @Nullable String e164, boolean highTrust) { public static @NonNull Recipient externalPush(@Nullable ServiceId serviceId, @Nullable String e164, boolean highTrust) {
if (ACI.UNKNOWN.equals(aci)) { if (ServiceId.UNKNOWN.equals(serviceId)) {
throw new AssertionError(); throw new AssertionError();
} }
RecipientDatabase db = SignalDatabase.recipients(); RecipientDatabase db = SignalDatabase.recipients();
RecipientId recipientId = db.getAndPossiblyMerge(aci, e164, highTrust); RecipientId recipientId = db.getAndPossiblyMerge(serviceId, e164, highTrust);
Recipient resolved = resolved(recipientId); Recipient resolved = resolved(recipientId);
@ -237,9 +238,9 @@ public class Recipient {
Log.w(TAG, "Resolved " + recipientId + ", but got back a recipient with " + resolved.getId()); Log.w(TAG, "Resolved " + recipientId + ", but got back a recipient with " + resolved.getId());
} }
if (highTrust && !resolved.isRegistered() && aci != null) { if (highTrust && !resolved.isRegistered() && serviceId != null) {
Log.w(TAG, "External high-trust push was locally marked unregistered. Marking as registered."); Log.w(TAG, "External high-trust push was locally marked unregistered. Marking as registered.");
db.markRegistered(recipientId, aci); db.markRegistered(recipientId, serviceId);
} else if (highTrust && !resolved.isRegistered()) { } else if (highTrust && !resolved.isRegistered()) {
Log.w(TAG, "External high-trust push was locally marked unregistered, but we don't have an ACI, so we can't do anything.", new Throwable()); Log.w(TAG, "External high-trust push was locally marked unregistered, but we don't have an ACI, so we can't do anything.", new Throwable());
} }
@ -305,7 +306,7 @@ public class Recipient {
* or serialized groupId. * or serialized groupId.
* *
* If the identifier is a UUID of a Signal user, prefer using * If the identifier is a UUID of a Signal user, prefer using
* {@link #externalPush(Context, ACI, String, boolean)} or its overload, as this will let us associate * {@link #externalPush(ServiceId, String, boolean)} or its overload, as this will let us associate
* the phone number with the recipient. * the phone number with the recipient.
*/ */
@WorkerThread @WorkerThread
@ -317,7 +318,7 @@ public class Recipient {
if (UuidUtil.isUuid(identifier)) { if (UuidUtil.isUuid(identifier)) {
ACI uuid = ACI.parseOrThrow(identifier); ACI uuid = ACI.parseOrThrow(identifier);
id = db.getOrInsertFromAci(uuid); id = db.getOrInsertFromServiceId(uuid);
} else if (GroupId.isEncodedGroup(identifier)) { } else if (GroupId.isEncodedGroup(identifier)) {
id = db.getOrInsertFromGroupId(GroupId.parseOrThrow(identifier)); id = db.getOrInsertFromGroupId(GroupId.parseOrThrow(identifier));
} else if (NumberUtil.isValidEmail(identifier)) { } else if (NumberUtil.isValidEmail(identifier)) {
@ -337,7 +338,7 @@ public class Recipient {
Recipient(@NonNull RecipientId id) { Recipient(@NonNull RecipientId id) {
this.id = id; this.id = id;
this.resolving = true; this.resolving = true;
this.aci = null; this.serviceId = null;
this.pni = null; this.pni = null;
this.username = null; this.username = null;
this.e164 = null; this.e164 = null;
@ -392,9 +393,9 @@ public class Recipient {
public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) { public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) {
this.id = id; this.id = id;
this.resolving = !resolved; this.resolving = !resolved;
this.aci = details.aci; this.serviceId = details.serviceId;
this.pni = details.pni; this.pni = details.pni;
this.username = details.username; this.username = details.username;
this.e164 = details.e164; this.e164 = details.e164;
this.email = details.email; this.email = details.email;
@ -614,8 +615,8 @@ public class Recipient {
return StringUtil.isolateBidi(name); return StringUtil.isolateBidi(name);
} }
public @NonNull Optional<ACI> getAci() { public @NonNull Optional<ServiceId> getServiceId() {
return Optional.fromNullable(aci); return Optional.fromNullable(serviceId);
} }
public @NonNull Optional<PNI> getPni() { public @NonNull Optional<PNI> getPni() {
@ -646,16 +647,6 @@ public class Recipient {
return Optional.fromNullable(e164).or(Optional.fromNullable(email)); return Optional.fromNullable(e164).or(Optional.fromNullable(email));
} }
public @NonNull ACI requireAci() {
ACI resolved = resolving ? resolve().aci : aci;
if (resolved == null) {
throw new MissingAddressError(id);
}
return resolved;
}
public @NonNull PNI requirePni() { public @NonNull PNI requirePni() {
PNI resolved = resolving ? resolve().pni : pni; PNI resolved = resolving ? resolve().pni : pni;
@ -706,16 +697,12 @@ public class Recipient {
return getE164().isPresent(); return getE164().isPresent();
} }
public boolean hasAci() { public boolean hasServiceId() {
return getAci().isPresent(); return getServiceId().isPresent();
} }
public boolean hasPni() { public boolean isServiceIdOnly() {
return getPni().isPresent(); return hasServiceId() && !hasSmsAddress();
}
public boolean isAciOnly() {
return hasAci() && !hasSmsAddress();
} }
public @NonNull GroupId requireGroupId() { public @NonNull GroupId requireGroupId() {
@ -728,36 +715,31 @@ public class Recipient {
return resolved; return resolved;
} }
public boolean hasServiceIdentifier() {
return aci != null || e164 != null;
}
/** /**
* @return A string identifier able to be used with the Signal service. Prefers ACI, and if not * The {@link ServiceId} of the user if available, otherwise throw.
* available, will return an E164 number.
*/ */
public @NonNull String requireServiceId() { public @NonNull ServiceId requireServiceId() {
Recipient resolved = resolving ? resolve() : this; ServiceId resolved = resolving ? resolve().serviceId : serviceId;
if (resolved.getAci().isPresent()) { if (resolved == null) {
return resolved.requireAci().toString(); throw new MissingAddressError(id);
} else {
return getE164().get();
} }
return resolved;
} }
/** /**
* @return A single string to represent the recipient, in order of precedence: * @return A single string to represent the recipient, in order of precedence:
* *
* Group ID > ACI > Phone > Email * Group ID > ServiceId > Phone > Email
*/ */
public @NonNull String requireStringId() { public @NonNull String requireStringId() {
Recipient resolved = resolving ? resolve() : this; Recipient resolved = resolving ? resolve() : this;
if (resolved.isGroup()) { if (resolved.isGroup()) {
return resolved.requireGroupId().toString(); return resolved.requireGroupId().toString();
} else if (resolved.getAci().isPresent()) { } else if (resolved.getServiceId().isPresent()) {
return resolved.requireAci().toString(); return resolved.requireServiceId().toString();
} }
return requireSmsAddress(); return requireSmsAddress();
@ -1214,7 +1196,7 @@ public class Recipient {
profileSharing == other.profileSharing && profileSharing == other.profileSharing &&
lastProfileFetch == other.lastProfileFetch && lastProfileFetch == other.lastProfileFetch &&
forceSmsSelection == other.forceSmsSelection && forceSmsSelection == other.forceSmsSelection &&
Objects.equals(aci, other.aci) && Objects.equals(serviceId, other.serviceId) &&
Objects.equals(username, other.username) && Objects.equals(username, other.username) &&
Objects.equals(e164, other.e164) && Objects.equals(e164, other.e164) &&
Objects.equals(email, other.email) && Objects.equals(email, other.email) &&

View file

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
@ -32,7 +33,7 @@ import java.util.List;
public class RecipientDetails { public class RecipientDetails {
final ACI aci; final ServiceId serviceId;
final PNI pni; final PNI pni;
final String username; final String username;
final String e164; final String e164;
@ -99,7 +100,7 @@ public class RecipientDetails {
this.systemContactPhoto = Util.uri(record.getSystemContactPhotoUri()); this.systemContactPhoto = Util.uri(record.getSystemContactPhotoUri());
this.customLabel = record.getSystemPhoneLabel(); this.customLabel = record.getSystemPhoneLabel();
this.contactUri = Util.uri(record.getSystemContactUri()); this.contactUri = Util.uri(record.getSystemContactUri());
this.aci = record.getAci(); this.serviceId = record.getServiceId();
this.pni = record.getPni(); this.pni = record.getPni();
this.username = record.getUsername(); this.username = record.getUsername();
this.e164 = record.getE164(); this.e164 = record.getE164();
@ -156,9 +157,9 @@ public class RecipientDetails {
this.groupAvatarId = null; this.groupAvatarId = null;
this.systemContactPhoto = null; this.systemContactPhoto = null;
this.customLabel = null; this.customLabel = null;
this.contactUri = null; this.contactUri = null;
this.aci = null; this.serviceId = null;
this.pni = null; this.pni = null;
this.username = null; this.username = null;
this.e164 = null; this.e164 = null;
this.email = null; this.email = null;
@ -210,7 +211,7 @@ public class RecipientDetails {
public static @NonNull RecipientDetails forIndividual(@NonNull Context context, @NonNull RecipientRecord settings) { public static @NonNull RecipientDetails forIndividual(@NonNull Context context, @NonNull RecipientRecord settings) {
boolean systemContact = !settings.getSystemProfileName().isEmpty(); boolean systemContact = !settings.getSystemProfileName().isEmpty();
boolean isSelf = (settings.getE164() != null && settings.getE164().equals(SignalStore.account().getE164())) || boolean isSelf = (settings.getE164() != null && settings.getE164().equals(SignalStore.account().getE164())) ||
(settings.getAci() != null && settings.getAci().equals(SignalStore.account().getAci())); (settings.getServiceId() != null && settings.getServiceId().equals(SignalStore.account().getAci()));
boolean isReleaseChannel = settings.getId().equals(SignalStore.releaseChannelValues().getReleaseChannelRecipientId()); boolean isReleaseChannel = settings.getId().equals(SignalStore.releaseChannelValues().getReleaseChannelRecipientId());
RegisteredState registeredState = settings.getRegistered(); RegisteredState registeredState = settings.getRegistered();

View file

@ -15,13 +15,13 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.DelimiterUtil; import org.thoughtcrime.securesms.util.DelimiterUtil;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class RecipientId implements Parcelable, Comparable<RecipientId> { public class RecipientId implements Parcelable, Comparable<RecipientId> {
@ -55,7 +55,7 @@ public class RecipientId implements Parcelable, Comparable<RecipientId> {
@AnyThread @AnyThread
public static @NonNull RecipientId from(@NonNull SignalServiceAddress address) { public static @NonNull RecipientId from(@NonNull SignalServiceAddress address) {
return from(address.getAci(), address.getNumber().orNull(), false); return from(address.getServiceId(), address.getNumber().orNull(), false);
} }
/** /**
@ -78,7 +78,7 @@ public class RecipientId implements Parcelable, Comparable<RecipientId> {
*/ */
@AnyThread @AnyThread
public static @NonNull RecipientId fromHighTrust(@NonNull SignalServiceAddress address) { public static @NonNull RecipientId fromHighTrust(@NonNull SignalServiceAddress address) {
return from(address.getAci(), address.getNumber().orNull(), true); return from(address.getServiceId(), address.getNumber().orNull(), true);
} }
/** /**
@ -86,17 +86,17 @@ public class RecipientId implements Parcelable, Comparable<RecipientId> {
*/ */
@AnyThread @AnyThread
@SuppressLint("WrongThread") @SuppressLint("WrongThread")
public static @NonNull RecipientId from(@Nullable ACI aci, @Nullable String e164) { public static @NonNull RecipientId from(@Nullable ServiceId aci, @Nullable String e164) {
return from(aci, e164, false); return from(aci, e164, false);
} }
@AnyThread @AnyThread
@SuppressLint("WrongThread") @SuppressLint("WrongThread")
private static @NonNull RecipientId from(@Nullable ACI aci, @Nullable String e164, boolean highTrust) { private static @NonNull RecipientId from(@Nullable ServiceId aci, @Nullable String e164, boolean highTrust) {
RecipientId recipientId = RecipientIdCache.INSTANCE.get(aci, e164); RecipientId recipientId = RecipientIdCache.INSTANCE.get(aci, e164);
if (recipientId == null) { if (recipientId == null) {
Recipient recipient = Recipient.externalPush(ApplicationDependencies.getApplication(), aci, e164, highTrust); Recipient recipient = Recipient.externalPush(aci, e164, highTrust);
RecipientIdCache.INSTANCE.put(recipient); RecipientIdCache.INSTANCE.put(recipient);
recipientId = recipient.getId(); recipientId = recipient.getId();
} }

View file

@ -5,11 +5,10 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID;
/** /**
* Thread safe cache that allows faster looking up of {@link RecipientId}s without hitting the database. * Thread safe cache that allows faster looking up of {@link RecipientId}s without hitting the database.
@ -34,22 +33,22 @@ final class RecipientIdCache {
} }
synchronized void put(@NonNull Recipient recipient) { synchronized void put(@NonNull Recipient recipient) {
RecipientId recipientId = recipient.getId(); RecipientId recipientId = recipient.getId();
Optional<String> e164 = recipient.getE164(); Optional<String> e164 = recipient.getE164();
Optional<ACI> aci = recipient.getAci(); Optional<ServiceId> serviceId = recipient.getServiceId();
if (e164.isPresent()) { if (e164.isPresent()) {
ids.put(e164.get(), recipientId); ids.put(e164.get(), recipientId);
} }
if (aci.isPresent()) { if (serviceId.isPresent()) {
ids.put(aci.get(), recipientId); ids.put(serviceId.get(), recipientId);
} }
} }
synchronized @Nullable RecipientId get(@Nullable ACI aci, @Nullable String e164) { synchronized @Nullable RecipientId get(@Nullable ServiceId serviceId, @Nullable String e164) {
if (aci != null && e164 != null) { if (serviceId != null && e164 != null) {
RecipientId recipientIdByAci = ids.get(aci); RecipientId recipientIdByAci = ids.get(serviceId);
if (recipientIdByAci == null) return null; if (recipientIdByAci == null) return null;
RecipientId recipientIdByE164 = ids.get(e164); RecipientId recipientIdByE164 = ids.get(e164);
@ -58,13 +57,13 @@ final class RecipientIdCache {
if (recipientIdByAci.equals(recipientIdByE164)) { if (recipientIdByAci.equals(recipientIdByE164)) {
return recipientIdByAci; return recipientIdByAci;
} else { } else {
ids.remove(aci); ids.remove(serviceId);
ids.remove(e164); ids.remove(e164);
Log.w(TAG, "Seen invalid RecipientIdCacheState"); Log.w(TAG, "Seen invalid RecipientIdCacheState");
return null; return null;
} }
} else if (aci != null) { } else if (serviceId != null) {
return ids.get(aci); return ids.get(serviceId);
} else if (e164 != null) { } else if (e164 != null) {
return ids.get(e164); return ids.get(e164);
} }

View file

@ -49,11 +49,11 @@ public class RecipientUtil {
{ {
recipient = recipient.resolve(); recipient = recipient.resolve();
if (!recipient.getAci().isPresent() && !recipient.getE164().isPresent()) { if (!recipient.getServiceId().isPresent() && !recipient.getE164().isPresent()) {
throw new AssertionError(recipient.getId() + " - No UUID or phone number!"); throw new AssertionError(recipient.getId() + " - No UUID or phone number!");
} }
if (!recipient.getAci().isPresent()) { if (!recipient.getServiceId().isPresent()) {
Log.i(TAG, recipient.getId() + " is missing a UUID..."); Log.i(TAG, recipient.getId() + " is missing a UUID...");
RegisteredState state = DirectoryHelper.refreshDirectoryFor(context, recipient, false); RegisteredState state = DirectoryHelper.refreshDirectoryFor(context, recipient, false);
@ -61,8 +61,8 @@ public class RecipientUtil {
Log.i(TAG, "Successfully performed a UUID fetch for " + recipient.getId() + ". Registered: " + state); Log.i(TAG, "Successfully performed a UUID fetch for " + recipient.getId() + ". Registered: " + state);
} }
if (recipient.hasAci()) { if (recipient.hasServiceId()) {
return new SignalServiceAddress(recipient.requireAci(), Optional.fromNullable(recipient.resolve().getE164().orNull())); return new SignalServiceAddress(recipient.requireServiceId(), Optional.fromNullable(recipient.resolve().getE164().orNull()));
} else { } else {
throw new NotFoundException(recipient.getId() + " is not registered!"); throw new NotFoundException(recipient.getId() + " is not registered!");
} }
@ -81,7 +81,7 @@ public class RecipientUtil {
return Stream.of(recipients) return Stream.of(recipients)
.map(Recipient::resolve) .map(Recipient::resolve)
.map(r -> new SignalServiceAddress(r.requireAci(), r.getE164().orNull())) .map(r -> new SignalServiceAddress(r.requireServiceId(), r.getE164().orNull()))
.toList(); .toList();
} }
@ -93,7 +93,7 @@ public class RecipientUtil {
{ {
List<Recipient> recipientsWithoutUuids = Stream.of(recipients) List<Recipient> recipientsWithoutUuids = Stream.of(recipients)
.map(Recipient::resolve) .map(Recipient::resolve)
.filterNot(Recipient::hasAci) .filterNot(Recipient::hasServiceId)
.toList(); .toList();
if (recipientsWithoutUuids.size() > 0) { if (recipientsWithoutUuids.size() > 0) {
@ -178,7 +178,7 @@ public class RecipientUtil {
ApplicationDependencies.getJobManager().add(new MultiDeviceBlockedUpdateJob()); ApplicationDependencies.getJobManager().add(new MultiDeviceBlockedUpdateJob());
StorageSyncHelper.scheduleSyncForDataChange(); StorageSyncHelper.scheduleSyncForDataChange();
if (recipient.hasServiceIdentifier()) { if (recipient.hasServiceId()) {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forAccept(recipient.getId())); ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forAccept(recipient.getId()));
} }
} }

View file

@ -37,8 +37,9 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.KbsPinData; import org.whispersystems.signalservice.api.KbsPinData;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.internal.ServiceResponse; import org.whispersystems.signalservice.internal.ServiceResponse;
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse; import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
@ -142,15 +143,15 @@ public final class RegistrationRepository {
SignalServiceAccountDataStoreImpl aciProtocolStore = ApplicationDependencies.getProtocolStore().aci(); SignalServiceAccountDataStoreImpl aciProtocolStore = ApplicationDependencies.getProtocolStore().aci();
SignalServiceAccountDataStoreImpl pniProtocolStore = ApplicationDependencies.getProtocolStore().pni(); SignalServiceAccountDataStoreImpl pniProtocolStore = ApplicationDependencies.getProtocolStore().pni();
generateAndRegisterPreKeys(aci, accountManager, aciProtocolStore, SignalStore.account().aciPreKeys()); generateAndRegisterPreKeys(ServiceIdType.ACI, accountManager, aciProtocolStore, SignalStore.account().aciPreKeys());
generateAndRegisterPreKeys(pni, accountManager, pniProtocolStore, SignalStore.account().pniPreKeys()); generateAndRegisterPreKeys(ServiceIdType.PNI, accountManager, pniProtocolStore, SignalStore.account().pniPreKeys());
if (registrationData.isFcm()) { if (registrationData.isFcm()) {
accountManager.setGcmId(Optional.fromNullable(registrationData.getFcmToken())); accountManager.setGcmId(Optional.fromNullable(registrationData.getFcmToken()));
} }
RecipientDatabase recipientDatabase = SignalDatabase.recipients(); RecipientDatabase recipientDatabase = SignalDatabase.recipients();
RecipientId selfId = Recipient.externalPush(context, aci, registrationData.getE164(), true).getId(); RecipientId selfId = Recipient.externalPush(aci, registrationData.getE164(), true).getId();
recipientDatabase.setProfileSharing(selfId, true); recipientDatabase.setProfileSharing(selfId, true);
recipientDatabase.markRegisteredOrThrow(selfId, aci); recipientDatabase.markRegisteredOrThrow(selfId, aci);
@ -175,7 +176,7 @@ public final class RegistrationRepository {
PinState.onRegistration(context, kbsData, pin, hasPin); PinState.onRegistration(context, kbsData, pin, hasPin);
} }
private void generateAndRegisterPreKeys(@NonNull AccountIdentifier accountId, private void generateAndRegisterPreKeys(@NonNull ServiceIdType serviceIdType,
@NonNull SignalServiceAccountManager accountManager, @NonNull SignalServiceAccountManager accountManager,
@NonNull SignalProtocolStore protocolStore, @NonNull SignalProtocolStore protocolStore,
@NonNull PreKeyMetadataStore metadataStore) @NonNull PreKeyMetadataStore metadataStore)
@ -184,7 +185,7 @@ public final class RegistrationRepository {
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, true); SignedPreKeyRecord signedPreKey = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore, true);
List<PreKeyRecord> oneTimePreKeys = PreKeyUtil.generateAndStoreOneTimePreKeys(protocolStore, metadataStore); List<PreKeyRecord> oneTimePreKeys = PreKeyUtil.generateAndStoreOneTimePreKeys(protocolStore, metadataStore);
accountManager.setPreKeys(accountId, protocolStore.getIdentityKeyPair().getPublicKey(), signedPreKey, oneTimePreKeys); accountManager.setPreKeys(serviceIdType, protocolStore.getIdentityKeyPair().getPublicKey(), signedPreKey, oneTimePreKeys);
metadataStore.setSignedPreKeyRegistered(true); metadataStore.setSignedPreKeyRegistered(true);
} }

View file

@ -83,7 +83,7 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
seen.add(Recipient.self()); seen.add(Recipient.self());
for (GroupCall.RemoteDeviceState device : remoteDeviceStates) { for (GroupCall.RemoteDeviceState device : remoteDeviceStates) {
Recipient recipient = Recipient.externalPush(context, ACI.from(device.getUserId()), null, false); Recipient recipient = Recipient.externalPush(ACI.from(device.getUserId()), null, false);
CallParticipantId callParticipantId = new CallParticipantId(device.getDemuxId(), recipient.getId()); CallParticipantId callParticipantId = new CallParticipantId(device.getDemuxId(), recipient.getId());
CallParticipant callParticipant = participants.get(callParticipantId); CallParticipant callParticipant = participants.get(callParticipantId);

View file

@ -123,8 +123,8 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId); webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId);
List<UUID> members = new ArrayList<>(peekInfo.getJoinedMembers()); List<UUID> members = new ArrayList<>(peekInfo.getJoinedMembers());
if (!members.contains(Recipient.self().requireAci().uuid())) { if (!members.contains(Recipient.self().requireServiceId().uuid())) {
members.add(Recipient.self().requireAci().uuid()); members.add(Recipient.self().requireServiceId().uuid());
} }
webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, WebRtcUtil.isCallFull(peekInfo)); webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, WebRtcUtil.isCallFull(peekInfo));
@ -149,7 +149,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
String eraId = WebRtcUtil.getGroupCallEraId(groupCall); String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId); webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId);
List<UUID> members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireAci().uuid()).toList(); List<UUID> members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireServiceId().uuid()).toList();
webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, false); webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, false);
currentState = currentState.builder() currentState = currentState.builder()

View file

@ -114,7 +114,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
} }
List<Recipient> callParticipants = Stream.of(peekInfo.getJoinedMembers()) List<Recipient> callParticipants = Stream.of(peekInfo.getJoinedMembers())
.map(uuid -> Recipient.externalPush(context, ACI.from(uuid), null, false)) .map(uuid -> Recipient.externalPush(ACI.from(uuid), null, false))
.toList(); .toList();
WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder() WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder()

View file

@ -138,7 +138,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
.changeCallSetupState(RemotePeer.GROUP_CALL_ID) .changeCallSetupState(RemotePeer.GROUP_CALL_ID)
.isRemoteVideoOffer(true) .isRemoteVideoOffer(true)
.ringId(ringId) .ringId(ringId)
.ringerRecipient(Recipient.externalPush(context, ACI.from(uuid), null, false)) .ringerRecipient(Recipient.externalPush(ACI.from(uuid), null, false))
.commit() .commit()
.changeCallInfoState() .changeCallInfoState()
.activePeer(new RemotePeer(currentState.getCallInfoState().getCallRecipient().getId(), RemotePeer.GROUP_CALL_ID)) .activePeer(new RemotePeer(currentState.getCallInfoState().getCallRecipient().getId(), RemotePeer.GROUP_CALL_ID))

View file

@ -154,7 +154,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
serviceExecutor.execute(() -> { serviceExecutor.execute(() -> {
if (needsToSetSelfUuid) { if (needsToSetSelfUuid) {
try { try {
callManager.setSelfUuid(Recipient.self().requireAci().uuid()); callManager.setSelfUuid(Recipient.self().requireServiceId().uuid());
needsToSetSelfUuid = false; needsToSetSelfUuid = false;
} catch (CallException e) { } catch (CallException e) {
Log.w(TAG, "Unable to set self UUID on CallManager", e); Log.w(TAG, "Unable to set self UUID on CallManager", e);

View file

@ -13,9 +13,9 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalContactRecord; import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState; import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState;
import java.util.Arrays; import java.util.Arrays;
@ -51,10 +51,10 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
if (address == null) { if (address == null) {
Log.w(TAG, "No address on the ContentRecord -- marking as invalid."); Log.w(TAG, "No address on the ContentRecord -- marking as invalid.");
return true; return true;
} else if (!address.hasValidAci()) { } else if (!address.hasValidServiceId()) {
Log.w(TAG, "Found a ContactRecord without a UUID -- marking as invalid."); Log.w(TAG, "Found a ContactRecord without a UUID -- marking as invalid.");
return true; return true;
} else if ((self.getAci().isPresent() && address.getAci().equals(self.requireAci())) || } else if ((self.getServiceId().isPresent() && address.getServiceId().equals(self.requireServiceId())) ||
(self.getE164().isPresent() && address.getNumber().equals(self.getE164()))) (self.getE164().isPresent() && address.getNumber().equals(self.getE164())))
{ {
Log.w(TAG, "Found a ContactRecord for ourselves -- marking as invalid."); Log.w(TAG, "Found a ContactRecord for ourselves -- marking as invalid.");
@ -67,7 +67,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
@Override @Override
@NonNull Optional<SignalContactRecord> getMatching(@NonNull SignalContactRecord remote, @NonNull StorageKeyGenerator keyGenerator) { @NonNull Optional<SignalContactRecord> getMatching(@NonNull SignalContactRecord remote, @NonNull StorageKeyGenerator keyGenerator) {
SignalServiceAddress address = remote.getAddress(); SignalServiceAddress address = remote.getAddress();
Optional<RecipientId> byUuid = recipientDatabase.getByAci(address.getAci()); Optional<RecipientId> byUuid = recipientDatabase.getByServiceId(address.getServiceId());
Optional<RecipientId> byE164 = address.getNumber().isPresent() ? recipientDatabase.getByE164(address.getNumber().get()) : Optional.absent(); Optional<RecipientId> byE164 = address.getNumber().isPresent() ? recipientDatabase.getByE164(address.getNumber().get()) : Optional.absent();
return byUuid.or(byE164).transform(recipientDatabase::getRecordForSync) return byUuid.or(byE164).transform(recipientDatabase::getRecordForSync)
@ -98,9 +98,9 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
} }
byte[] unknownFields = remote.serializeUnknownFields(); byte[] unknownFields = remote.serializeUnknownFields();
ACI aci = local.getAddress().getAci() == ACI.UNKNOWN ? remote.getAddress().getAci() : local.getAddress().getAci(); ServiceId serviceId = local.getAddress().getServiceId() == ServiceId.UNKNOWN ? remote.getAddress().getServiceId() : local.getAddress().getServiceId();
String e164 = remote.getAddress().getNumber().or(local.getAddress().getNumber()).orNull(); String e164 = remote.getAddress().getNumber().or(local.getAddress().getNumber()).orNull();
SignalServiceAddress address = new SignalServiceAddress(aci, e164); SignalServiceAddress address = new SignalServiceAddress(serviceId, e164);
byte[] profileKey = remote.getProfileKey().or(local.getProfileKey()).orNull(); byte[] profileKey = remote.getProfileKey().or(local.getProfileKey()).orNull();
String username = remote.getUsername().or(local.getUsername()).or(""); String username = remote.getUsername().or(local.getUsername()).or("");
IdentityState identityState = remote.getIdentityState(); IdentityState identityState = remote.getIdentityState();
@ -146,7 +146,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
@Override @Override
public int compare(@NonNull SignalContactRecord lhs, @NonNull SignalContactRecord rhs) { public int compare(@NonNull SignalContactRecord lhs, @NonNull SignalContactRecord rhs) {
if (Objects.equals(lhs.getAddress().getAci(), rhs.getAddress().getAci()) || if (Objects.equals(lhs.getAddress().getServiceId(), rhs.getAddress().getServiceId()) ||
Objects.equals(lhs.getAddress().getNumber(), rhs.getAddress().getNumber())) Objects.equals(lhs.getAddress().getNumber(), rhs.getAddress().getNumber()))
{ {
return 0; return 0;

View file

@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues; import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
import org.thoughtcrime.securesms.subscription.Subscriber; import org.thoughtcrime.securesms.subscription.Subscriber;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord; import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
import org.whispersystems.signalservice.api.storage.SignalContactRecord; import org.whispersystems.signalservice.api.storage.SignalContactRecord;
@ -83,7 +84,7 @@ public final class StorageSyncModels {
private static @NonNull SignalAccountRecord.PinnedConversation localToRemotePinnedConversation(@NonNull RecipientRecord settings) { private static @NonNull SignalAccountRecord.PinnedConversation localToRemotePinnedConversation(@NonNull RecipientRecord settings) {
switch (settings.getGroupType()) { switch (settings.getGroupType()) {
case NONE : return SignalAccountRecord.PinnedConversation.forContact(new SignalServiceAddress(settings.getAci(), settings.getE164())); case NONE : return SignalAccountRecord.PinnedConversation.forContact(new SignalServiceAddress(settings.getServiceId(), settings.getE164()));
case SIGNAL_V1: return SignalAccountRecord.PinnedConversation.forGroupV1(settings.getGroupId().requireV1().getDecodedId()); case SIGNAL_V1: return SignalAccountRecord.PinnedConversation.forGroupV1(settings.getGroupId().requireV1().getDecodedId());
case SIGNAL_V2: return SignalAccountRecord.PinnedConversation.forGroupV2(settings.getSyncExtras().getGroupMasterKey().serialize()); case SIGNAL_V2: return SignalAccountRecord.PinnedConversation.forGroupV2(settings.getSyncExtras().getGroupMasterKey().serialize());
default : throw new AssertionError("Unexpected group type!"); default : throw new AssertionError("Unexpected group type!");
@ -91,13 +92,13 @@ public final class StorageSyncModels {
} }
private static @NonNull SignalContactRecord localToRemoteContact(@NonNull RecipientRecord recipient, byte[] rawStorageId) { private static @NonNull SignalContactRecord localToRemoteContact(@NonNull RecipientRecord recipient, byte[] rawStorageId) {
if (recipient.getAci() == null && recipient.getE164() == null) { if (recipient.getServiceId() == null && recipient.getE164() == null) {
throw new AssertionError("Must have either a UUID or a phone number!"); throw new AssertionError("Must have either a UUID or a phone number!");
} }
ACI aci = recipient.getAci() != null ? recipient.getAci() : ACI.UNKNOWN; ServiceId serviceId = recipient.getServiceId() != null ? recipient.getServiceId() : ServiceId.UNKNOWN;
return new SignalContactRecord.Builder(rawStorageId, new SignalServiceAddress(aci, recipient.getE164()), recipient.getSyncExtras().getStorageProto()) return new SignalContactRecord.Builder(rawStorageId, new SignalServiceAddress(serviceId, recipient.getE164()), recipient.getSyncExtras().getStorageProto())
.setProfileKey(recipient.getProfileKey()) .setProfileKey(recipient.getProfileKey())
.setGivenName(recipient.getProfileName().getGivenName()) .setGivenName(recipient.getProfileName().getGivenName())
.setFamilyName(recipient.getProfileName().getFamilyName()) .setFamilyName(recipient.getProfileName().getFamilyName())

View file

@ -142,7 +142,7 @@ public final class StorageSyncValidations {
if (insert.getContact().isPresent()) { if (insert.getContact().isPresent()) {
SignalServiceAddress address = insert.getContact().get().getAddress(); SignalServiceAddress address = insert.getContact().get().getAddress();
if (self.requireE164().equals(address.getNumber().or("")) || self.requireAci().equals(address.getAci())) { if (self.requireE164().equals(address.getNumber().or("")) || self.requireServiceId().equals(address.getServiceId())) {
throw new SelfAddedAsContactError(); throw new SelfAddedAsContactError();
} }
} }

View file

@ -23,7 +23,7 @@ public final class BucketingUtil {
* Calculate a user bucket for a given feature flag, uuid, and part per modulus. * Calculate a user bucket for a given feature flag, uuid, and part per modulus.
* *
* @param key Feature flag key (e.g., "research.megaphone.1") * @param key Feature flag key (e.g., "research.megaphone.1")
* @param uuid Current user's UUID (see {@link Recipient#getAci()}) * @param uuid Current user's UUID (see {@link Recipient#getServiceId()})
* @param modulus Drives the bucketing parts per N (e.g., passing 1,000,000 indicates bucketing into parts per million) * @param modulus Drives the bucketing parts per N (e.g., passing 1,000,000 indicates bucketing into parts per million)
*/ */
public static long bucket(@NonNull String key, @NonNull UUID uuid, long modulus) { public static long bucket(@NonNull String key, @NonNull UUID uuid, long modulus) {

View file

@ -240,7 +240,7 @@ public class CommunicationActions {
SimpleTask.run(() -> { SimpleTask.run(() -> {
Recipient recipient = Recipient.external(activity, e164); Recipient recipient = Recipient.external(activity, e164);
if (!recipient.isRegistered() || !recipient.hasAci()) { if (!recipient.isRegistered() || !recipient.hasServiceId()) {
try { try {
DirectoryHelper.refreshDirectoryFor(activity, recipient, false); DirectoryHelper.refreshDirectoryFor(activity, recipient, false);
recipient = Recipient.resolved(recipient.getId()); recipient = Recipient.resolved(recipient.getId());

View file

@ -161,7 +161,7 @@ public final class IdentityUtil {
public static void processVerifiedMessage(Context context, VerifiedMessage verifiedMessage) { public static void processVerifiedMessage(Context context, VerifiedMessage verifiedMessage) {
try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
SignalIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities(); SignalIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities();
Recipient recipient = Recipient.externalPush(context, verifiedMessage.getDestination()); Recipient recipient = Recipient.externalPush(verifiedMessage.getDestination());
Optional<IdentityRecord> identityRecord = identityStore.getIdentityRecord(recipient.getId()); Optional<IdentityRecord> identityRecord = identityStore.getIdentityRecord(recipient.getId());
if (!identityRecord.isPresent() && verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT) { if (!identityRecord.isPresent() && verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT) {

View file

@ -76,12 +76,12 @@ public final class LocaleFeatureFlags {
Map<String, Integer> countryCodeValues = parseCountryValues(serialized, 0); Map<String, Integer> countryCodeValues = parseCountryValues(serialized, 0);
Recipient self = Recipient.self(); Recipient self = Recipient.self();
if (countryCodeValues.isEmpty() || !self.getE164().isPresent() || !self.getAci().isPresent()) { if (countryCodeValues.isEmpty() || !self.getE164().isPresent() || !self.getServiceId().isPresent()) {
return false; return false;
} }
long countEnabled = getCountryValue(countryCodeValues, self.getE164().or(""), 0); long countEnabled = getCountryValue(countryCodeValues, self.getE164().or(""), 0);
long currentUserBucket = BucketingUtil.bucket(flag, self.requireAci().uuid(), 1_000_000); long currentUserBucket = BucketingUtil.bucket(flag, self.requireServiceId().uuid(), 1_000_000);
return countEnabled > currentUserBucket; return countEnabled > currentUserBucket;
} }

View file

@ -10,7 +10,6 @@ import org.signal.core.util.logging.Log;
import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.profiles.ProfileKey; import org.signal.zkgroup.profiles.ProfileKey;
import org.thoughtcrime.securesms.badges.models.Badge; import org.thoughtcrime.securesms.badges.models.Badge;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase;
@ -284,7 +283,7 @@ public final class ProfileUtil {
ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey(); ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey();
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager(); SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
String avatarPath = accountManager.setVersionedProfile(Recipient.self().requireAci(), String avatarPath = accountManager.setVersionedProfile(SignalStore.account().requireAci(),
profileKey, profileKey,
profileName.serialize(), profileName.serialize(),
about, about,
@ -321,8 +320,8 @@ public final class ProfileUtil {
private static @NonNull SignalServiceAddress toSignalServiceAddress(@NonNull Context context, @NonNull Recipient recipient) throws IOException { private static @NonNull SignalServiceAddress toSignalServiceAddress(@NonNull Context context, @NonNull Recipient recipient) throws IOException {
if (recipient.getRegistered() == RecipientDatabase.RegisteredState.NOT_REGISTERED) { if (recipient.getRegistered() == RecipientDatabase.RegisteredState.NOT_REGISTERED) {
if (recipient.hasAci()) { if (recipient.hasServiceId()) {
return new SignalServiceAddress(recipient.requireAci(), recipient.getE164().orNull()); return new SignalServiceAddress(recipient.requireServiceId(), recipient.getE164().orNull());
} else { } else {
throw new IOException(recipient.getId() + " not registered!"); throw new IOException(recipient.getId() + " not registered!");
} }

View file

@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.util
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.recipients.RecipientId
import org.whispersystems.signalservice.api.push.ACI import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.push.SignalServiceAddress
/** /**
@ -11,10 +11,10 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress
*/ */
class RecipientAccessList(private val recipients: List<Recipient>) : List<Recipient> by recipients { class RecipientAccessList(private val recipients: List<Recipient>) : List<Recipient> by recipients {
private val byAci: Map<ACI, Recipient> by lazy { private val byServiceId: Map<ServiceId, Recipient> by lazy {
recipients recipients
.filter { it.hasAci() } .filter { it.hasServiceId() }
.associateBy { it.requireAci() } .associateBy { it.requireServiceId() }
} }
private val byE164: Map<String, Recipient> by lazy { private val byE164: Map<String, Recipient> by lazy {
@ -24,8 +24,8 @@ class RecipientAccessList(private val recipients: List<Recipient>) : List<Recipi
} }
fun requireByAddress(address: SignalServiceAddress): Recipient { fun requireByAddress(address: SignalServiceAddress): Recipient {
if (byAci.containsKey(address.aci)) { if (byServiceId.containsKey(address.serviceId)) {
return byAci[address.aci]!! return byServiceId[address.serviceId]!!
} else if (address.number.isPresent && byE164.containsKey(address.number.get())) { } else if (address.number.isPresent && byE164.containsKey(address.number.get())) {
return byE164[address.number.get()]!! return byE164[address.number.get()]!!
} else { } else {

View file

@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
@ -51,15 +52,15 @@ public class UsernameUtil {
} }
@WorkerThread @WorkerThread
public static @NonNull Optional<ACI> fetchAciForUsername(@NonNull Context context, @NonNull String username) { public static @NonNull Optional<ServiceId> fetchAciForUsername(@NonNull String username) {
Optional<RecipientId> localId = SignalDatabase.recipients().getByUsername(username); Optional<RecipientId> localId = SignalDatabase.recipients().getByUsername(username);
if (localId.isPresent()) { if (localId.isPresent()) {
Recipient recipient = Recipient.resolved(localId.get()); Recipient recipient = Recipient.resolved(localId.get());
if (recipient.getAci().isPresent()) { if (recipient.getServiceId().isPresent()) {
Log.i(TAG, "Found username locally -- using associated UUID."); Log.i(TAG, "Found username locally -- using associated UUID.");
return recipient.getAci(); return recipient.getServiceId();
} else { } else {
Log.w(TAG, "Found username locally, but it had no associated UUID! Clearing it."); Log.w(TAG, "Found username locally, but it had no associated UUID! Clearing it.");
SignalDatabase.recipients().clearUsernameIfExists(username); SignalDatabase.recipients().clearUsernameIfExists(username);

View file

@ -16,7 +16,6 @@ import android.text.TextUtils;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -35,7 +34,6 @@ import android.widget.Toast;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
@ -212,18 +210,18 @@ public class VerifyDisplayFragment extends Fragment implements ViewTreeObserver.
//noinspection WrongThread //noinspection WrongThread
Recipient resolved = recipient.resolve(); Recipient resolved = recipient.resolve();
if (FeatureFlags.verifyV2() && resolved.getAci().isPresent()) { if (FeatureFlags.verifyV2() && resolved.getServiceId().isPresent()) {
Log.i(TAG, "Using UUID (version 2)."); Log.i(TAG, "Using UUID (version 2).");
version = 2; version = 2;
localId = Recipient.self().requireAci().toByteArray(); localId = Recipient.self().requireServiceId().toByteArray();
remoteId = resolved.requireAci().toByteArray(); remoteId = resolved.requireServiceId().toByteArray();
} else if (!FeatureFlags.verifyV2() && resolved.getE164().isPresent()) { } else if (!FeatureFlags.verifyV2() && resolved.getE164().isPresent()) {
Log.i(TAG, "Using E164 (version 1)."); Log.i(TAG, "Using E164 (version 1).");
version = 1; version = 1;
localId = Recipient.self().requireE164().getBytes(); localId = Recipient.self().requireE164().getBytes();
remoteId = resolved.requireE164().getBytes(); remoteId = resolved.requireE164().getBytes();
} else { } else {
Log.w(TAG, String.format(Locale.ENGLISH, "Could not show proper verification! verifyV2: %s, hasUuid: %s, hasE164: %s", FeatureFlags.verifyV2(), resolved.getAci().isPresent(), resolved.getE164().isPresent())); Log.w(TAG, String.format(Locale.ENGLISH, "Could not show proper verification! verifyV2: %s, hasUuid: %s, hasE164: %s", FeatureFlags.verifyV2(), resolved.getServiceId().isPresent(), resolved.getE164().isPresent()));
new MaterialAlertDialogBuilder(requireContext()) new MaterialAlertDialogBuilder(requireContext())
.setMessage(getString(R.string.VerifyIdentityActivity_you_must_first_exchange_messages_in_order_to_view, resolved.getDisplayName(requireContext()))) .setMessage(getString(R.string.VerifyIdentityActivity_you_must_first_exchange_messages_in_order_to_view, resolved.getDisplayName(requireContext())))
.setPositiveButton(android.R.string.ok, (dialog, which) -> requireActivity().finish()) .setPositiveButton(android.R.string.ok, (dialog, which) -> requireActivity().finish())

View file

@ -26,6 +26,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedMember;
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember; import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
import org.thoughtcrime.securesms.testutil.MainThreadUtil; import org.thoughtcrime.securesms.testutil.MainThreadUtil;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Arrays; import java.util.Arrays;
@ -1351,14 +1352,14 @@ public final class GroupsV2UpdateMessageProducerTest {
} }
private void assertSingleChangeMentioning(DecryptedGroupChange change, List<UUID> expectedMentions) { private void assertSingleChangeMentioning(DecryptedGroupChange change, List<UUID> expectedMentions) {
List<ACI> expectedMentionAcis = expectedMentions.stream().map(ACI::from).collect(Collectors.toList()); List<ServiceId> expectedMentionSids = expectedMentions.stream().map(ServiceId::from).collect(Collectors.toList());
List<UpdateDescription> changes = producer.describeChanges(null, change); List<UpdateDescription> changes = producer.describeChanges(null, change);
assertThat(changes.size(), is(1)); assertThat(changes.size(), is(1));
UpdateDescription description = changes.get(0); UpdateDescription description = changes.get(0);
assertThat(description.getMentioned(), is(expectedMentionAcis)); assertThat(description.getMentioned(), is(expectedMentionSids));
if (expectedMentions.isEmpty()) { if (expectedMentions.isEmpty()) {
assertTrue(description.isStringStatic()); assertTrue(description.isStringStatic());
@ -1397,8 +1398,8 @@ public final class GroupsV2UpdateMessageProducerTest {
} }
private static @NonNull GroupsV2UpdateMessageProducer.DescribeMemberStrategy createDescriber(@NonNull Map<UUID, String> map) { private static @NonNull GroupsV2UpdateMessageProducer.DescribeMemberStrategy createDescriber(@NonNull Map<UUID, String> map) {
return aci -> { return serviceId -> {
String name = map.get(aci.uuid()); String name = map.get(serviceId.uuid());
assertNotNull(name); assertNotNull(name);
return name; return name;
}; };

View file

@ -266,7 +266,7 @@ public final class RecipientIdCacheTest {
Recipient mock = mock(Recipient.class); Recipient mock = mock(Recipient.class);
when(mock.getId()).thenReturn(recipientId); when(mock.getId()).thenReturn(recipientId);
when(mock.getAci()).thenReturn(Optional.fromNullable(aci)); when(mock.getServiceId()).thenReturn(Optional.fromNullable(aci));
when(mock.getE164()).thenReturn(Optional.fromNullable(e164)); when(mock.getE164()).thenReturn(Optional.fromNullable(e164));
return mock; return mock;

View file

@ -27,10 +27,8 @@ import org.whispersystems.signalservice.api.storage.StorageId;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -57,7 +55,7 @@ public final class StorageSyncHelperTest {
private static final Recipient SELF = mock(Recipient.class); private static final Recipient SELF = mock(Recipient.class);
static { static {
when(SELF.getAci()).thenReturn(Optional.of(ACI_SELF)); when(SELF.getServiceId()).thenReturn(Optional.of(ACI_SELF));
when(SELF.getE164()).thenReturn(Optional.of(E164_SELF)); when(SELF.getE164()).thenReturn(Optional.of(E164_SELF));
when(SELF.resolve()).thenReturn(SELF); when(SELF.resolve()).thenReturn(SELF);
} }

View file

@ -35,8 +35,9 @@ import org.whispersystems.signalservice.api.payments.CurrencyConversions;
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential; import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfileWrite; import org.whispersystems.signalservice.api.profiles.SignalServiceProfileWrite;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
import org.whispersystems.signalservice.api.push.exceptions.NoContentException; import org.whispersystems.signalservice.api.push.exceptions.NoContentException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
@ -420,18 +421,18 @@ public class SignalServiceAccountManager {
* *
* @throws IOException * @throws IOException
*/ */
public void setPreKeys(AccountIdentifier accountId, IdentityKey identityKey, SignedPreKeyRecord signedPreKey, List<PreKeyRecord> oneTimePreKeys) public void setPreKeys(ServiceIdType serviceIdType, IdentityKey identityKey, SignedPreKeyRecord signedPreKey, List<PreKeyRecord> oneTimePreKeys)
throws IOException throws IOException
{ {
this.pushServiceSocket.registerPreKeys(accountId, identityKey, signedPreKey, oneTimePreKeys); this.pushServiceSocket.registerPreKeys(serviceIdType, identityKey, signedPreKey, oneTimePreKeys);
} }
/** /**
* @return The server's count of currently available (eg. unused) prekeys for this user. * @return The server's count of currently available (eg. unused) prekeys for this user.
* @throws IOException * @throws IOException
*/ */
public int getPreKeysCount(AccountIdentifier accountId) throws IOException { public int getPreKeysCount(ServiceIdType serviceIdType) throws IOException {
return this.pushServiceSocket.getAvailablePreKeys(accountId); return this.pushServiceSocket.getAvailablePreKeys(serviceIdType);
} }
/** /**
@ -440,22 +441,22 @@ public class SignalServiceAccountManager {
* @param signedPreKey The client's new signed prekey. * @param signedPreKey The client's new signed prekey.
* @throws IOException * @throws IOException
*/ */
public void setSignedPreKey(AccountIdentifier accountId, SignedPreKeyRecord signedPreKey) throws IOException { public void setSignedPreKey(ServiceIdType serviceIdType, SignedPreKeyRecord signedPreKey) throws IOException {
this.pushServiceSocket.setCurrentSignedPreKey(accountId, signedPreKey); this.pushServiceSocket.setCurrentSignedPreKey(serviceIdType, signedPreKey);
} }
/** /**
* @return The server's view of the client's current signed prekey. * @return The server's view of the client's current signed prekey.
* @throws IOException * @throws IOException
*/ */
public SignedPreKeyEntity getSignedPreKey(AccountIdentifier accountId) throws IOException { public SignedPreKeyEntity getSignedPreKey(ServiceIdType serviceIdType) throws IOException {
return this.pushServiceSocket.getCurrentSignedPreKey(accountId); return this.pushServiceSocket.getCurrentSignedPreKey(serviceIdType);
} }
/** /**
* @return True if the identifier corresponds to a registered user, otherwise false. * @return True if the identifier corresponds to a registered user, otherwise false.
*/ */
public boolean isIdentifierRegistered(AccountIdentifier identifier) throws IOException { public boolean isIdentifierRegistered(ServiceId identifier) throws IOException {
return pushServiceSocket.isIdentifierRegistered(identifier); return pushServiceSocket.isIdentifierRegistered(identifier);
} }
@ -815,11 +816,11 @@ public class SignalServiceAccountManager {
profileAvatarData); profileAvatarData);
} }
public Optional<ProfileKeyCredential> resolveProfileKeyCredential(ACI aci, ProfileKey profileKey, Locale locale) public Optional<ProfileKeyCredential> resolveProfileKeyCredential(ServiceId serviceId, ProfileKey profileKey, Locale locale)
throws NonSuccessfulResponseCodeException, PushNetworkException throws NonSuccessfulResponseCodeException, PushNetworkException
{ {
try { try {
ProfileAndCredential credential = this.pushServiceSocket.retrieveVersionedProfileAndCredential(aci.uuid(), profileKey, Optional.absent(), locale).get(10, TimeUnit.SECONDS); ProfileAndCredential credential = this.pushServiceSocket.retrieveVersionedProfileAndCredential(serviceId.uuid(), profileKey, Optional.absent(), locale).get(10, TimeUnit.SECONDS);
return credential.getProfileKeyCredential(); return credential.getProfileKeyCredential();
} catch (InterruptedException | TimeoutException e) { } catch (InterruptedException | TimeoutException e) {
throw new PushNetworkException(e); throw new PushNetworkException(e);

View file

@ -1,6 +1,6 @@
package org.whispersystems.signalservice.api; package org.whispersystems.signalservice.api;
import org.whispersystems.signalservice.api.push.AccountIdentifier; import org.whispersystems.signalservice.api.push.ServiceId;
/** /**
* And extension of the normal protocol store interface that has additional methods that are needed * And extension of the normal protocol store interface that has additional methods that are needed
@ -11,7 +11,7 @@ public interface SignalServiceDataStore {
/** /**
* @return A {@link SignalServiceAccountDataStore} for the specified account. * @return A {@link SignalServiceAccountDataStore} for the specified account.
*/ */
SignalServiceAccountDataStore get(AccountIdentifier accountIdentifier); SignalServiceAccountDataStore get(ServiceId accountIdentifier);
/** /**
* @return A {@link SignalServiceAccountDataStore} for the ACI account. * @return A {@link SignalServiceAccountDataStore} for the ACI account.

View file

@ -21,10 +21,10 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStickerManifes
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential; import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException; import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
import org.whispersystems.signalservice.api.util.CredentialsProvider; import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration; import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
import org.whispersystems.signalservice.internal.push.PushServiceSocket; import org.whispersystems.signalservice.internal.push.PushServiceSocket;
import org.whispersystems.signalservice.internal.push.SignalServiceEnvelopeEntity; import org.whispersystems.signalservice.internal.push.SignalServiceEnvelopeEntity;
@ -43,7 +43,6 @@ import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.UUID;
/** /**
* The primary interface for receiving Signal Service messages. * The primary interface for receiving Signal Service messages.
@ -91,13 +90,13 @@ public class SignalServiceMessageReceiver {
SignalServiceProfile.RequestType requestType, SignalServiceProfile.RequestType requestType,
Locale locale) Locale locale)
{ {
ACI aci = address.getAci(); ServiceId serviceId = address.getServiceId();
if (profileKey.isPresent()) { if (profileKey.isPresent()) {
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) { if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
return socket.retrieveVersionedProfileAndCredential(aci.uuid(), profileKey.get(), unidentifiedAccess, locale); return socket.retrieveVersionedProfileAndCredential(serviceId.uuid(), profileKey.get(), unidentifiedAccess, locale);
} else { } else {
return FutureTransformers.map(socket.retrieveVersionedProfile(aci.uuid(), profileKey.get(), unidentifiedAccess, locale), profile -> { return FutureTransformers.map(socket.retrieveVersionedProfile(serviceId.uuid(), profileKey.get(), unidentifiedAccess, locale), profile -> {
return new ProfileAndCredential(profile, return new ProfileAndCredential(profile,
SignalServiceProfile.RequestType.PROFILE, SignalServiceProfile.RequestType.PROFILE,
Optional.absent()); Optional.absent());

View file

@ -64,6 +64,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage;
import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
import org.whispersystems.signalservice.api.push.exceptions.MalformedResponseException; import org.whispersystems.signalservice.api.push.exceptions.MalformedResponseException;
@ -118,7 +119,6 @@ import org.whispersystems.signalservice.internal.push.http.ResumableUploadSpec;
import org.whispersystems.signalservice.internal.util.Util; import org.whispersystems.signalservice.internal.util.Util;
import org.whispersystems.util.Base64; import org.whispersystems.util.Base64;
import org.whispersystems.util.ByteArrayUtil; import org.whispersystems.util.ByteArrayUtil;
import org.whispersystems.util.FlagUtil;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -795,7 +795,7 @@ public class SignalServiceMessageSender {
DataMessage.Quote.Builder quoteBuilder = DataMessage.Quote.newBuilder() DataMessage.Quote.Builder quoteBuilder = DataMessage.Quote.newBuilder()
.setId(message.getQuote().get().getId()) .setId(message.getQuote().get().getId())
.setText(message.getQuote().get().getText()) .setText(message.getQuote().get().getText())
.setAuthorUuid(message.getQuote().get().getAuthor().getAci().toString()); .setAuthorUuid(message.getQuote().get().getAuthor().getServiceId().toString());
if (!message.getQuote().get().getMentions().isEmpty()) { if (!message.getQuote().get().getMentions().isEmpty()) {
for (SignalServiceDataMessage.Mention mention : message.getQuote().get().getMentions()) { for (SignalServiceDataMessage.Mention mention : message.getQuote().get().getMentions()) {
@ -891,7 +891,7 @@ public class SignalServiceMessageSender {
.setEmoji(message.getReaction().get().getEmoji()) .setEmoji(message.getReaction().get().getEmoji())
.setRemove(message.getReaction().get().isRemove()) .setRemove(message.getReaction().get().isRemove())
.setTargetSentTimestamp(message.getReaction().get().getTargetSentTimestamp()) .setTargetSentTimestamp(message.getReaction().get().getTargetSentTimestamp())
.setTargetAuthorUuid(message.getReaction().get().getTargetAuthor().getAci().toString()); .setTargetAuthorUuid(message.getReaction().get().getTargetAuthor().getServiceId().toString());
builder.setReaction(reactionBuilder.build()); builder.setReaction(reactionBuilder.build());
builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.REACTIONS_VALUE, builder.getRequiredProtocolVersion())); builder.setRequiredProtocolVersion(Math.max(DataMessage.ProtocolVersion.REACTIONS_VALUE, builder.getRequiredProtocolVersion()));
@ -1071,7 +1071,7 @@ public class SignalServiceMessageSender {
if (result.getSuccess() != null) { if (result.getSuccess() != null) {
SyncMessage.Sent.UnidentifiedDeliveryStatus.Builder builder = SyncMessage.Sent.UnidentifiedDeliveryStatus.newBuilder(); SyncMessage.Sent.UnidentifiedDeliveryStatus.Builder builder = SyncMessage.Sent.UnidentifiedDeliveryStatus.newBuilder();
builder.setDestinationUuid(result.getAddress().getAci().toString()); builder.setDestinationUuid(result.getAddress().getServiceId().toString());
if (result.getAddress().getNumber().isPresent()) { if (result.getAddress().getNumber().isPresent()) {
builder.setDestinationE164(result.getAddress().getNumber().get()); builder.setDestinationE164(result.getAddress().getNumber().get());
@ -1084,7 +1084,7 @@ public class SignalServiceMessageSender {
} }
if (recipient.isPresent()) { if (recipient.isPresent()) {
sentMessage.setDestinationUuid(recipient.get().getAci().toString()); sentMessage.setDestinationUuid(recipient.get().getServiceId().toString());
if (recipient.get().getNumber().isPresent()) { if (recipient.get().getNumber().isPresent()) {
sentMessage.setDestinationE164(recipient.get().getNumber().get()); sentMessage.setDestinationE164(recipient.get().getNumber().get());
@ -1112,7 +1112,7 @@ public class SignalServiceMessageSender {
for (ReadMessage readMessage : readMessages) { for (ReadMessage readMessage : readMessages) {
SyncMessage.Read.Builder readBuilder = SyncMessage.Read.newBuilder().setTimestamp(readMessage.getTimestamp()); SyncMessage.Read.Builder readBuilder = SyncMessage.Read.newBuilder().setTimestamp(readMessage.getTimestamp());
readBuilder.setSenderUuid(readMessage.getSender().getAci().toString()); readBuilder.setSenderUuid(readMessage.getSender().getServiceId().toString());
if (readMessage.getSender().getNumber().isPresent()) { if (readMessage.getSender().getNumber().isPresent()) {
readBuilder.setSenderE164(readMessage.getSender().getNumber().get()); readBuilder.setSenderE164(readMessage.getSender().getNumber().get());
@ -1131,7 +1131,7 @@ public class SignalServiceMessageSender {
for (ViewedMessage readMessage : readMessages) { for (ViewedMessage readMessage : readMessages) {
SyncMessage.Viewed.Builder viewedBuilder = SyncMessage.Viewed.newBuilder().setTimestamp(readMessage.getTimestamp()); SyncMessage.Viewed.Builder viewedBuilder = SyncMessage.Viewed.newBuilder().setTimestamp(readMessage.getTimestamp());
viewedBuilder.setSenderUuid(readMessage.getSender().getAci().toString()); viewedBuilder.setSenderUuid(readMessage.getSender().getServiceId().toString());
if (readMessage.getSender().getNumber().isPresent()) { if (readMessage.getSender().getNumber().isPresent()) {
viewedBuilder.setSenderE164(readMessage.getSender().getNumber().get()); viewedBuilder.setSenderE164(readMessage.getSender().getNumber().get());
@ -1148,7 +1148,7 @@ public class SignalServiceMessageSender {
SyncMessage.Builder builder = createSyncMessageBuilder(); SyncMessage.Builder builder = createSyncMessageBuilder();
SyncMessage.ViewOnceOpen.Builder viewOnceBuilder = SyncMessage.ViewOnceOpen.newBuilder().setTimestamp(readMessage.getTimestamp()); SyncMessage.ViewOnceOpen.Builder viewOnceBuilder = SyncMessage.ViewOnceOpen.newBuilder().setTimestamp(readMessage.getTimestamp());
viewOnceBuilder.setSenderUuid(readMessage.getSender().getAci().toString()); viewOnceBuilder.setSenderUuid(readMessage.getSender().getServiceId().toString());
if (readMessage.getSender().getNumber().isPresent()) { if (readMessage.getSender().getNumber().isPresent()) {
viewOnceBuilder.setSenderE164(readMessage.getSender().getNumber().get()); viewOnceBuilder.setSenderE164(readMessage.getSender().getNumber().get());
@ -1165,7 +1165,7 @@ public class SignalServiceMessageSender {
SyncMessage.Blocked.Builder blockedMessage = SyncMessage.Blocked.newBuilder(); SyncMessage.Blocked.Builder blockedMessage = SyncMessage.Blocked.newBuilder();
for (SignalServiceAddress address : blocked.getAddresses()) { for (SignalServiceAddress address : blocked.getAddresses()) {
blockedMessage.addUuids(address.getAci().toString()); blockedMessage.addUuids(address.getServiceId().toString());
if (address.getNumber().isPresent()) { if (address.getNumber().isPresent()) {
blockedMessage.addNumbers(address.getNumber().get()); blockedMessage.addNumbers(address.getNumber().get());
} }
@ -1268,7 +1268,7 @@ public class SignalServiceMessageSender {
if (message.getPerson().get().getNumber().isPresent()) { if (message.getPerson().get().getNumber().isPresent()) {
responseMessage.setThreadE164(message.getPerson().get().getNumber().get()); responseMessage.setThreadE164(message.getPerson().get().getNumber().get());
} }
responseMessage.setThreadUuid(message.getPerson().get().getAci().toString()); responseMessage.setThreadUuid(message.getPerson().get().getServiceId().toString());
} }
switch (message.getType()) { switch (message.getType()) {
@ -1301,7 +1301,7 @@ public class SignalServiceMessageSender {
SyncMessage.OutgoingPayment.Builder paymentMessage = SyncMessage.OutgoingPayment.newBuilder(); SyncMessage.OutgoingPayment.Builder paymentMessage = SyncMessage.OutgoingPayment.newBuilder();
if (message.getRecipient().isPresent()) { if (message.getRecipient().isPresent()) {
paymentMessage.setRecipientUuid(message.getRecipient().get().getAci().toString()); paymentMessage.setRecipientUuid(message.getRecipient().get().getServiceId().toString());
} }
if (message.getNote().isPresent()) { if (message.getNote().isPresent()) {
@ -1353,7 +1353,7 @@ public class SignalServiceMessageSender {
verifiedMessageBuilder.setNullMessage(ByteString.copyFrom(nullMessage)); verifiedMessageBuilder.setNullMessage(ByteString.copyFrom(nullMessage));
verifiedMessageBuilder.setIdentityKey(ByteString.copyFrom(verifiedMessage.getIdentityKey().serialize())); verifiedMessageBuilder.setIdentityKey(ByteString.copyFrom(verifiedMessage.getIdentityKey().serialize()));
verifiedMessageBuilder.setDestinationUuid(verifiedMessage.getDestination().getAci().toString()); verifiedMessageBuilder.setDestinationUuid(verifiedMessage.getDestination().getServiceId().toString());
if (verifiedMessage.getDestination().getNumber().isPresent()) { if (verifiedMessage.getDestination().getNumber().isPresent()) {
verifiedMessageBuilder.setDestinationE164(verifiedMessage.getDestination().getNumber().get()); verifiedMessageBuilder.setDestinationE164(verifiedMessage.getDestination().getNumber().get());
@ -1745,12 +1745,12 @@ public class SignalServiceMessageSender {
Preconditions.checkArgument(recipients.size() == unidentifiedAccess.size(), "[" + timestamp + "] Unidentified access mismatch!"); Preconditions.checkArgument(recipients.size() == unidentifiedAccess.size(), "[" + timestamp + "] Unidentified access mismatch!");
Map<ACI, UnidentifiedAccess> accessByAci = new HashMap<>(); Map<ServiceId, UnidentifiedAccess> accessBySid = new HashMap<>();
Iterator<SignalServiceAddress> addressIterator = recipients.iterator(); Iterator<SignalServiceAddress> addressIterator = recipients.iterator();
Iterator<UnidentifiedAccess> accessIterator = unidentifiedAccess.iterator(); Iterator<UnidentifiedAccess> accessIterator = unidentifiedAccess.iterator();
while (addressIterator.hasNext()) { while (addressIterator.hasNext()) {
accessByAci.put(addressIterator.next().getAci(), accessIterator.next()); accessBySid.put(addressIterator.next().getServiceId(), accessIterator.next());
} }
for (int i = 0; i < RETRY_COUNT; i++) { for (int i = 0; i < RETRY_COUNT; i++) {
@ -1758,7 +1758,7 @@ public class SignalServiceMessageSender {
Set<SignalProtocolAddress> sharedWith = store.getSenderKeySharedWith(distributionId); Set<SignalProtocolAddress> sharedWith = store.getSenderKeySharedWith(distributionId);
List<SignalServiceAddress> needsSenderKey = targetInfo.destinations.stream() List<SignalServiceAddress> needsSenderKey = targetInfo.destinations.stream()
.filter(a -> !sharedWith.contains(a)) .filter(a -> !sharedWith.contains(a))
.map(a -> ACI.parseOrThrow(a.getName())) .map(a -> ServiceId.parseOrThrow(a.getName()))
.distinct() .distinct()
.map(SignalServiceAddress::new) .map(SignalServiceAddress::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -1767,7 +1767,7 @@ public class SignalServiceMessageSender {
SenderKeyDistributionMessage message = getOrCreateNewGroupSession(distributionId); SenderKeyDistributionMessage message = getOrCreateNewGroupSession(distributionId);
List<Optional<UnidentifiedAccessPair>> access = needsSenderKey.stream() List<Optional<UnidentifiedAccessPair>> access = needsSenderKey.stream()
.map(r -> { .map(r -> {
UnidentifiedAccess targetAccess = accessByAci.get(r.getAci()); UnidentifiedAccess targetAccess = accessBySid.get(r.getServiceId());
return Optional.of(new UnidentifiedAccessPair(targetAccess, targetAccess)); return Optional.of(new UnidentifiedAccessPair(targetAccess, targetAccess));
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -1779,8 +1779,8 @@ public class SignalServiceMessageSender {
.map(SendMessageResult::getAddress) .map(SendMessageResult::getAddress)
.collect(Collectors.toList()); .collect(Collectors.toList());
Set<String> successAcis = successes.stream().map(a -> a.getAci().toString()).collect(Collectors.toSet()); Set<String> successSids = successes.stream().map(a -> a.getServiceId().toString()).collect(Collectors.toSet());
Set<SignalProtocolAddress> successAddresses = targetInfo.destinations.stream().filter(a -> successAcis.contains(a.getName())).collect(Collectors.toSet()); Set<SignalProtocolAddress> successAddresses = targetInfo.destinations.stream().filter(a -> successSids.contains(a.getName())).collect(Collectors.toSet());
store.markSenderKeySharedWith(distributionId, successAddresses); store.markSenderKeySharedWith(distributionId, successAddresses);
@ -1794,12 +1794,12 @@ public class SignalServiceMessageSender {
.filter(r -> !r.isSuccess()) .filter(r -> !r.isSuccess())
.collect(Collectors.toList()); .collect(Collectors.toList());
Set<ACI> failedAddresses = trueFailures.stream() Set<ServiceId> failedAddresses = trueFailures.stream()
.map(result -> result.getAddress().getAci()) .map(result -> result.getAddress().getServiceId())
.collect(Collectors.toSet()); .collect(Collectors.toSet());
List<SendMessageResult> fakeNetworkFailures = recipients.stream() List<SendMessageResult> fakeNetworkFailures = recipients.stream()
.filter(r -> !failedAddresses.contains(r.getAci())) .filter(r -> !failedAddresses.contains(r.getServiceId()))
.map(SendMessageResult::networkFailure) .map(SendMessageResult::networkFailure)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -1914,7 +1914,7 @@ public class SignalServiceMessageSender {
List<SendMessageResult> success = recipients.keySet() List<SendMessageResult> success = recipients.keySet()
.stream() .stream()
.filter(r -> !unregistered.contains(r.getAci())) .filter(r -> !unregistered.contains(r.getServiceId()))
.map(a -> SendMessageResult.success(a, recipients.get(a), true, store.isMultiDevice(), -1, Optional.of(content))) .map(a -> SendMessageResult.success(a, recipients.get(a), true, store.isMultiDevice(), -1, Optional.of(content)))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -2064,7 +2064,7 @@ public class SignalServiceMessageSender {
List<SignalProtocolAddress> addresses = new ArrayList<>(devices.size()); List<SignalProtocolAddress> addresses = new ArrayList<>(devices.size());
for (int staleDeviceId : devices) { for (int staleDeviceId : devices) {
addresses.add(new SignalProtocolAddress(recipient.getAci().toString(), staleDeviceId)); addresses.add(new SignalProtocolAddress(recipient.getServiceId().toString(), staleDeviceId));
if (recipient.getNumber().isPresent()) { if (recipient.getNumber().isPresent()) {
addresses.add(new SignalProtocolAddress(recipient.getNumber().get(), staleDeviceId)); addresses.add(new SignalProtocolAddress(recipient.getNumber().get(), staleDeviceId));

View file

@ -100,7 +100,7 @@ public class SignalServiceCipher {
PushTransportDetails transport = new PushTransportDetails(); PushTransportDetails transport = new PushTransportDetails();
SignalProtocolAddress localProtocolAddress = new SignalProtocolAddress(localAddress.getIdentifier(), localDeviceId); SignalProtocolAddress localProtocolAddress = new SignalProtocolAddress(localAddress.getIdentifier(), localDeviceId);
SignalGroupCipher groupCipher = new SignalGroupCipher(sessionLock, new GroupCipher(signalProtocolStore, localProtocolAddress)); SignalGroupCipher groupCipher = new SignalGroupCipher(sessionLock, new GroupCipher(signalProtocolStore, localProtocolAddress));
SignalSealedSessionCipher sessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getAci().uuid(), localAddress.getNumber().orNull(), localDeviceId)); SignalSealedSessionCipher sessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orNull(), localDeviceId));
CiphertextMessage message = groupCipher.encrypt(distributionId.asUuid(), transport.getPaddedMessageBody(unpaddedMessage)); CiphertextMessage message = groupCipher.encrypt(distributionId.asUuid(), transport.getPaddedMessageBody(unpaddedMessage));
UnidentifiedSenderMessageContent messageContent = new UnidentifiedSenderMessageContent(message, UnidentifiedSenderMessageContent messageContent = new UnidentifiedSenderMessageContent(message,
senderCertificate, senderCertificate,
@ -117,7 +117,7 @@ public class SignalServiceCipher {
{ {
if (unidentifiedAccess.isPresent()) { if (unidentifiedAccess.isPresent()) {
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, destination)); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, destination));
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getAci().uuid(), localAddress.getNumber().orNull(), localDeviceId)); SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orNull(), localDeviceId));
return content.processSealedSender(sessionCipher, sealedSessionCipher, destination, unidentifiedAccess.get().getUnidentifiedCertificate()); return content.processSealedSender(sessionCipher, sealedSessionCipher, destination, unidentifiedAccess.get().getUnidentifiedCertificate());
} else { } else {
@ -208,7 +208,7 @@ public class SignalServiceCipher {
paddedMessage = new PlaintextContent(ciphertext).getBody(); paddedMessage = new PlaintextContent(ciphertext).getBody();
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent()); metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
} else if (envelope.isUnidentifiedSender()) { } else if (envelope.isUnidentifiedSender()) {
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getAci().uuid(), localAddress.getNumber().orNull(), localDeviceId)); SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orNull(), localDeviceId));
DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, ciphertext, envelope.getServerReceivedTimestamp()); DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, ciphertext, envelope.getServerReceivedTimestamp());
SignalServiceAddress resultAddress = new SignalServiceAddress(ACI.parseOrThrow(result.getSenderUuid()), result.getSenderE164()); SignalServiceAddress resultAddress = new SignalServiceAddress(ACI.parseOrThrow(result.getSenderUuid()), result.getSenderE164());
Optional<byte[]> groupId = result.getGroupId(); Optional<byte[]> groupId = result.getGroupId();

View file

@ -11,6 +11,7 @@ import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.OptionalUtil; import org.whispersystems.signalservice.api.util.OptionalUtil;
@ -610,17 +611,17 @@ public class SignalServiceDataMessage {
} }
public static class Mention { public static class Mention {
private final ACI aci; private final ServiceId aci;
private final int start; private final int start;
private final int length; private final int length;
public Mention(ACI aci, int start, int length) { public Mention(ServiceId aci, int start, int length) {
this.aci = aci; this.aci = aci;
this.start = start; this.start = start;
this.length = length; this.length = length;
} }
public ACI getAci() { public ServiceId getAci() {
return aci; return aci;
} }

View file

@ -12,7 +12,6 @@ import com.google.protobuf.InvalidProtocolBufferException;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope; import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope;
import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceEnvelopeProto; import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceEnvelopeProto;
import org.whispersystems.util.Base64; import org.whispersystems.util.Base64;
@ -71,7 +70,7 @@ public class SignalServiceEnvelope {
.setServerTimestamp(serverReceivedTimestamp); .setServerTimestamp(serverReceivedTimestamp);
if (sender.isPresent()) { if (sender.isPresent()) {
builder.setSourceUuid(sender.get().getAci().toString()); builder.setSourceUuid(sender.get().getServiceId().toString());
if (sender.get().getNumber().isPresent()) { if (sender.get().getNumber().isPresent()) {
builder.setSourceE164(sender.get().getNumber().get()); builder.setSourceE164(sender.get().getNumber().get());

View file

@ -37,7 +37,7 @@ public class DeviceContactsOutputStream extends ChunkedOutputStream {
private void writeContactDetails(DeviceContact contact) throws IOException { private void writeContactDetails(DeviceContact contact) throws IOException {
SignalServiceProtos.ContactDetails.Builder contactDetails = SignalServiceProtos.ContactDetails.newBuilder(); SignalServiceProtos.ContactDetails.Builder contactDetails = SignalServiceProtos.ContactDetails.newBuilder();
contactDetails.setUuid(contact.getAddress().getAci().toString()); contactDetails.setUuid(contact.getAddress().getServiceId().toString());
if (contact.getAddress().getNumber().isPresent()) { if (contact.getAddress().getNumber().isPresent()) {
contactDetails.setNumber(contact.getAddress().getNumber().get()); contactDetails.setNumber(contact.getAddress().getNumber().get());
@ -69,7 +69,7 @@ public class DeviceContactsOutputStream extends ChunkedOutputStream {
SignalServiceProtos.Verified.Builder verifiedBuilder = SignalServiceProtos.Verified.newBuilder() SignalServiceProtos.Verified.Builder verifiedBuilder = SignalServiceProtos.Verified.newBuilder()
.setIdentityKey(ByteString.copyFrom(contact.getVerified().get().getIdentityKey().serialize())) .setIdentityKey(ByteString.copyFrom(contact.getVerified().get().getIdentityKey().serialize()))
.setDestinationUuid(contact.getVerified().get().getDestination().getAci().toString()) .setDestinationUuid(contact.getVerified().get().getDestination().getServiceId().toString())
.setState(state); .setState(state);
if (contact.getVerified().get().getDestination().getNumber().isPresent()) { if (contact.getVerified().get().getDestination().getNumber().isPresent()) {

View file

@ -8,7 +8,7 @@ package org.whispersystems.signalservice.api.messages.multidevice;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.HashMap; import java.util.HashMap;
@ -21,26 +21,29 @@ public class SentTranscriptMessage {
private final long timestamp; private final long timestamp;
private final long expirationStartTimestamp; private final long expirationStartTimestamp;
private final SignalServiceDataMessage message; private final SignalServiceDataMessage message;
private final Map<String, Boolean> unidentifiedStatusByAci; private final Map<String, Boolean> unidentifiedStatusBySid;
private final Map<String, Boolean> unidentifiedStatusByE164; private final Map<String, Boolean> unidentifiedStatusByE164;
private final Set<SignalServiceAddress> recipients; private final Set<SignalServiceAddress> recipients;
private final boolean isRecipientUpdate; private final boolean isRecipientUpdate;
public SentTranscriptMessage(Optional<SignalServiceAddress> destination, long timestamp, SignalServiceDataMessage message, public SentTranscriptMessage(Optional<SignalServiceAddress> destination,
long expirationStartTimestamp, Map<SignalServiceAddress, Boolean> unidentifiedStatus, long timestamp,
SignalServiceDataMessage message,
long expirationStartTimestamp,
Map<SignalServiceAddress, Boolean> unidentifiedStatus,
boolean isRecipientUpdate) boolean isRecipientUpdate)
{ {
this.destination = destination; this.destination = destination;
this.timestamp = timestamp; this.timestamp = timestamp;
this.message = message; this.message = message;
this.expirationStartTimestamp = expirationStartTimestamp; this.expirationStartTimestamp = expirationStartTimestamp;
this.unidentifiedStatusByAci = new HashMap<>(); this.unidentifiedStatusBySid = new HashMap<>();
this.unidentifiedStatusByE164 = new HashMap<>(); this.unidentifiedStatusByE164 = new HashMap<>();
this.recipients = unidentifiedStatus.keySet(); this.recipients = unidentifiedStatus.keySet();
this.isRecipientUpdate = isRecipientUpdate; this.isRecipientUpdate = isRecipientUpdate;
for (Map.Entry<SignalServiceAddress, Boolean> entry : unidentifiedStatus.entrySet()) { for (Map.Entry<SignalServiceAddress, Boolean> entry : unidentifiedStatus.entrySet()) {
unidentifiedStatusByAci.put(entry.getKey().getAci().toString(), entry.getValue()); unidentifiedStatusBySid.put(entry.getKey().getServiceId().toString(), entry.getValue());
if (entry.getKey().getNumber().isPresent()) { if (entry.getKey().getNumber().isPresent()) {
unidentifiedStatusByE164.put(entry.getKey().getNumber().get(), entry.getValue()); unidentifiedStatusByE164.put(entry.getKey().getNumber().get(), entry.getValue());
@ -64,13 +67,13 @@ public class SentTranscriptMessage {
return message; return message;
} }
public boolean isUnidentified(ACI aci) { public boolean isUnidentified(ServiceId serviceId) {
return isUnidentified(aci.toString()); return isUnidentified(serviceId.toString());
} }
public boolean isUnidentified(String destination) { public boolean isUnidentified(String destination) {
if (unidentifiedStatusByAci.containsKey(destination)) { if (unidentifiedStatusBySid.containsKey(destination)) {
return unidentifiedStatusByAci.get(destination); return unidentifiedStatusBySid.get(destination);
} else if (unidentifiedStatusByE164.containsKey(destination)) { } else if (unidentifiedStatusByE164.containsKey(destination)) {
return unidentifiedStatusByE164.get(destination); return unidentifiedStatusByE164.get(destination);
} else { } else {

View file

@ -2,19 +2,15 @@ package org.whispersystems.signalservice.api.push;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Collection;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* 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 * 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. * this *specific type* of UUID.
*/ */
public final class ACI extends AccountIdentifier { public final class ACI extends ServiceId {
public static final ACI UNKNOWN = ACI.from(UuidUtil.UNKNOWN_UUID); public static final ACI UNKNOWN = ACI.from(UuidUtil.UNKNOWN_UUID);
@ -22,51 +18,15 @@ public final class ACI extends AccountIdentifier {
return new ACI(uuid); return new ACI(uuid);
} }
public static Optional<ACI> parse(String raw) {
return UuidUtil.parse(raw).transform(ACI::from);
}
public static ACI parseOrThrow(String raw) { public static ACI parseOrThrow(String raw) {
return from(UUID.fromString(raw)); return from(UUID.fromString(raw));
} }
public static ACI parseOrThrow(byte[] raw) {
return from(UuidUtil.parseOrThrow(raw));
}
public static ACI parseOrNull(String raw) { public static ACI parseOrNull(String raw) {
UUID uuid = UuidUtil.parseOrNull(raw); UUID uuid = UuidUtil.parseOrNull(raw);
return uuid != null ? from(uuid) : null; return uuid != null ? from(uuid) : null;
} }
public static ACI parseOrNull(byte[] raw) {
UUID uuid = UuidUtil.parseOrNull(raw);
return uuid != null ? from(uuid) : null;
}
public static ACI parseOrUnknown(String raw) {
ACI aci = parseOrNull(raw);
return aci != null ? aci : UNKNOWN;
}
public static ACI fromByteString(ByteString bytes) {
return parseOrThrow(bytes.toByteArray());
}
public static ACI fromByteStringOrNull(ByteString bytes) {
UUID uuid = UuidUtil.fromByteStringOrNull(bytes);
return uuid != null ? from(uuid) : null;
}
public static ACI fromByteStringOrUnknown(ByteString bytes) {
ACI uuid = fromByteStringOrNull(bytes);
return uuid != null ? uuid : UNKNOWN;
}
public static List<ACI> filterKnown(Collection<ACI> acis) {
return acis.stream().filter(aci -> !aci.equals(UNKNOWN)).collect(Collectors.toList());
}
private ACI(UUID uuid) { private ACI(UUID uuid) {
super(uuid); super(uuid);
} }
@ -79,13 +39,13 @@ public final class ACI extends AccountIdentifier {
return UuidUtil.toByteArray(uuid); return UuidUtil.toByteArray(uuid);
} }
public boolean isUnknown() {
return this.equals(UNKNOWN);
}
@Override @Override
public boolean isAci() { public boolean equals(Object other) {
return true; if (other instanceof ServiceId) {
return uuid.equals(((ServiceId) other).uuid);
} else {
return false;
}
} }
@Override @Override
@ -93,15 +53,6 @@ public final class ACI extends AccountIdentifier {
return uuid.hashCode(); return uuid.hashCode();
} }
@Override
public boolean equals(Object other) {
if (other instanceof ACI) {
return uuid.equals(((ACI) other).uuid);
} else {
return false;
}
}
@Override @Override
public String toString() { public String toString() {
return uuid.toString(); return uuid.toString();

View file

@ -1,30 +0,0 @@
package org.whispersystems.signalservice.api.push;
import java.util.UUID;
/**
* A wrapper around a UUID that represents an identifier for an account. Today, that is either an {@link ACI} or a {@link PNI}.
*/
public abstract class AccountIdentifier {
protected final UUID uuid;
protected AccountIdentifier(UUID uuid) {
this.uuid = uuid;
}
public UUID uuid() {
return uuid;
}
public abstract boolean isAci();
public final boolean isPni() {
return !isAci();
}
@Override
public String toString() {
return uuid.toString();
}
}

View file

@ -8,7 +8,7 @@ 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 * 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. * this *specific type* of UUID.
*/ */
public final class PNI extends AccountIdentifier { public final class PNI extends ServiceId {
public static PNI from(UUID uuid) { public static PNI from(UUID uuid) {
return new PNI(uuid); return new PNI(uuid);
@ -27,11 +27,6 @@ public final class PNI extends AccountIdentifier {
super(uuid); super(uuid);
} }
@Override
public boolean isAci() {
return false;
}
@Override @Override
public int hashCode() { public int hashCode() {
return uuid.hashCode(); return uuid.hashCode();

Some files were not shown because too many files have changed in this diff Show more