mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 01:40:07 +01:00
Use strongly-typed ACIs and PNIs everywhere.
This commit is contained in:
@@ -34,7 +34,7 @@ import org.thoughtcrime.securesms.jobs.CallSyncEventJob
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -605,11 +605,11 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
||||
fun insertOrUpdateGroupCallFromRingState(
|
||||
ringId: Long,
|
||||
groupRecipientId: RecipientId,
|
||||
ringerUUID: UUID,
|
||||
ringerAci: ACI,
|
||||
dateReceived: Long,
|
||||
ringState: RingUpdate
|
||||
) {
|
||||
val ringerRecipient = Recipient.externalPush(ServiceId.from(ringerUUID))
|
||||
val ringerRecipient = Recipient.externalPush(ringerAci)
|
||||
handleGroupRingState(ringId, groupRecipientId, ringerRecipient.id, dateReceived, ringState)
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.whispersystems.signalservice.api.groupsv2.GroupChangeReconstruct
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer
|
||||
import org.whispersystems.signalservice.api.push.DistributionId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil
|
||||
import java.io.Closeable
|
||||
import java.security.SecureRandom
|
||||
@@ -1215,7 +1216,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
val serviceId = recipient.serviceId
|
||||
|
||||
return if (serviceId.isPresent) {
|
||||
DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().uuid())
|
||||
DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().rawUuid)
|
||||
.map { it.role == Member.Role.ADMINISTRATOR }
|
||||
.orElse(false)
|
||||
} else {
|
||||
@@ -1232,7 +1233,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
return MemberLevel.NOT_A_MEMBER
|
||||
}
|
||||
|
||||
var memberLevel: Optional<MemberLevel> = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().uuid())
|
||||
var memberLevel: Optional<MemberLevel> = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, serviceId.get().rawUuid)
|
||||
.map { member ->
|
||||
if (member.role == Member.Role.ADMINISTRATOR) {
|
||||
MemberLevel.ADMINISTRATOR
|
||||
@@ -1242,12 +1243,12 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
}
|
||||
|
||||
if (memberLevel.isAbsent()) {
|
||||
memberLevel = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, serviceId.get().uuid())
|
||||
memberLevel = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, serviceId.get().rawUuid)
|
||||
.map { MemberLevel.PENDING_MEMBER }
|
||||
}
|
||||
|
||||
if (memberLevel.isAbsent()) {
|
||||
memberLevel = DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.requestingMembersList, serviceId.get().uuid())
|
||||
memberLevel = DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.requestingMembersList, serviceId.get().rawUuid)
|
||||
.map { _ -> MemberLevel.REQUESTING_MEMBER }
|
||||
}
|
||||
|
||||
@@ -1264,7 +1265,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
|
||||
fun getMemberRecipientIds(memberSet: MemberSet): List<RecipientId> {
|
||||
val includeSelf = memberSet.includeSelf
|
||||
val selfUuid = SignalStore.account().requireAci().uuid()
|
||||
val selfAciUuid = SignalStore.account().requireAci().rawUuid
|
||||
val recipients: MutableList<RecipientId> = ArrayList(decryptedGroup.membersCount + decryptedGroup.pendingMembersCount)
|
||||
|
||||
var unknownMembers = 0
|
||||
@@ -1273,8 +1274,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
for (uuid in DecryptedGroupUtil.toUuidList(decryptedGroup.membersList)) {
|
||||
if (UuidUtil.UNKNOWN_UUID == uuid) {
|
||||
unknownMembers++
|
||||
} else if (includeSelf || selfUuid != uuid) {
|
||||
recipients += RecipientId.from(ServiceId.from(uuid))
|
||||
} else if (includeSelf || selfAciUuid != uuid) {
|
||||
recipients += RecipientId.from(ACI.from(uuid))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1282,8 +1283,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
for (uuid in DecryptedGroupUtil.pendingToUuidList(decryptedGroup.pendingMembersList)) {
|
||||
if (UuidUtil.UNKNOWN_UUID == uuid) {
|
||||
unknownPending++
|
||||
} else if (includeSelf || selfUuid != uuid) {
|
||||
recipients += RecipientId.from(ServiceId.from(uuid))
|
||||
} else if (includeSelf || selfAciUuid != uuid) {
|
||||
recipients += RecipientId.from(ACI.from(uuid))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1301,7 +1302,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
.asSequence()
|
||||
.map { UuidUtil.fromByteStringOrNull(it.uuid) }
|
||||
.filterNotNull()
|
||||
.map { ServiceId.from(it) }
|
||||
.map { ACI.from(it) }
|
||||
.sortedBy { it.toString() }
|
||||
.toList()
|
||||
}
|
||||
@@ -1376,8 +1377,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
private fun gv2GroupActive(decryptedGroup: DecryptedGroup): Boolean {
|
||||
val aci = SignalStore.account().requireAci()
|
||||
|
||||
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, aci.uuid()).isPresent ||
|
||||
DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, aci.uuid()).isPresent
|
||||
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, aci.rawUuid).isPresent ||
|
||||
DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, aci.rawUuid).isPresent
|
||||
}
|
||||
|
||||
private fun List<UUID>.toRecipientIds(): MutableList<RecipientId> {
|
||||
@@ -1405,7 +1406,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
Log.w(TAG, "Saw an unknown UUID when mapping to RecipientIds!")
|
||||
null
|
||||
} else {
|
||||
val id = RecipientId.from(ServiceId.from(uuid))
|
||||
val id = RecipientId.from(ACI.from(uuid))
|
||||
val remapped = RemappedRecords.getInstance().getRecipient(id)
|
||||
if (remapped.isPresent) {
|
||||
Log.w(TAG, "Saw that $id remapped to $remapped. Using the mapping.")
|
||||
|
||||
@@ -70,6 +70,14 @@ class IdentityTable internal constructor(context: Context?, databaseHelper: Sign
|
||||
"""
|
||||
}
|
||||
|
||||
fun getIdentityStoreRecord(serviceId: ServiceId?): IdentityStoreRecord? {
|
||||
return if (serviceId != null) {
|
||||
getIdentityStoreRecord(serviceId.toString())
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getIdentityStoreRecord(addressName: String): IdentityStoreRecord? {
|
||||
readableDatabase
|
||||
.select()
|
||||
|
||||
@@ -96,7 +96,7 @@ public final class MentionUtil {
|
||||
BodyRangeList.Builder builder = BodyRangeList.newBuilder();
|
||||
|
||||
for (Mention mention : mentions) {
|
||||
String uuid = Recipient.resolved(mention.getRecipientId()).requireServiceId().toString();
|
||||
String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString();
|
||||
builder.addRanges(BodyRangeList.BodyRange.newBuilder()
|
||||
.setMentionUuid(uuid)
|
||||
.setStart(mention.getStart())
|
||||
|
||||
@@ -142,6 +142,7 @@ import org.thoughtcrime.securesms.util.Util
|
||||
import org.thoughtcrime.securesms.util.isStory
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage
|
||||
import java.io.Closeable
|
||||
import java.io.IOException
|
||||
@@ -845,7 +846,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val threadId = threads.getOrCreateThreadIdFor(recipient)
|
||||
val messageId: MessageId = writableDatabase.withinTransaction { db ->
|
||||
val self = Recipient.self()
|
||||
val markRead = joinedUuids.contains(self.requireServiceId().uuid()) || self.id == sender
|
||||
val markRead = joinedUuids.contains(self.requireServiceId().rawUuid) || self.id == sender
|
||||
val updateDetails: ByteArray = GroupCallUpdateDetails.newBuilder()
|
||||
.setEraId(eraId)
|
||||
.setStartedCallUuid(Recipient.resolved(sender).requireServiceId().toString())
|
||||
@@ -919,7 +920,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
}
|
||||
|
||||
val updateDetail = GroupCallUpdateDetailsUtil.parse(message.body)
|
||||
val containsSelf = joinedUuids.contains(SignalStore.account().requireAci().uuid())
|
||||
val containsSelf = joinedUuids.contains(SignalStore.account().requireAci().rawUuid)
|
||||
val sameEraId = updateDetail.eraId == eraId && !Util.isEmpty(eraId)
|
||||
val inCallUuids = if (sameEraId) joinedUuids.map { it.toString() } else emptyList()
|
||||
val contentValues = contentValuesOf(
|
||||
@@ -954,7 +955,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
MmsReader(cursor).use { reader ->
|
||||
val record = reader.getNext() ?: return@withinTransaction false
|
||||
val groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(record.body)
|
||||
val containsSelf = peekJoinedUuids.contains(SignalStore.account().requireAci().uuid())
|
||||
val containsSelf = peekJoinedUuids.contains(SignalStore.account().requireAci().rawUuid)
|
||||
val sameEraId = groupCallUpdateDetails.eraId == peekGroupCallEraId && !Util.isEmpty(peekGroupCallEraId)
|
||||
|
||||
val inCallUuids = if (sameEraId) {
|
||||
@@ -3088,9 +3089,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
val members: MutableSet<RecipientId> = mutableSetOf()
|
||||
|
||||
if (message.isGroupUpdate && message.isV2Group) {
|
||||
// TODO [greyson][ServiceId] pending members could be ACI's or PNI's
|
||||
members += message.requireGroupV2Properties().allActivePendingAndRemovedMembers
|
||||
.distinct()
|
||||
.map { uuid -> RecipientId.from(ServiceId.from(uuid)) }
|
||||
.map { uuid -> RecipientId.from(ACI.from(uuid)) }
|
||||
.toList()
|
||||
|
||||
members -= Recipient.self().id
|
||||
|
||||
@@ -3,8 +3,9 @@ package org.thoughtcrime.securesms.database
|
||||
import app.cash.exhaustive.Exhaustive
|
||||
import org.thoughtcrime.securesms.database.model.RecipientRecord
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.whispersystems.signalservice.api.push.ACI
|
||||
import org.whispersystems.signalservice.api.push.PNI
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI
|
||||
|
||||
/**
|
||||
* Encapsulates data around processing a tuple of user data into a user entry in [RecipientTable].
|
||||
@@ -15,18 +16,20 @@ data class PnpDataSet(
|
||||
val pni: PNI?,
|
||||
val aci: ACI?,
|
||||
val byE164: RecipientId?,
|
||||
val byPniSid: RecipientId?,
|
||||
val byPniOnly: RecipientId?,
|
||||
val byAciSid: RecipientId?,
|
||||
val byPni: RecipientId?,
|
||||
val byAci: RecipientId?,
|
||||
val e164Record: RecipientRecord? = null,
|
||||
val pniSidRecord: RecipientRecord? = null,
|
||||
val aciSidRecord: RecipientRecord? = null
|
||||
val pniRecord: RecipientRecord? = null,
|
||||
val aciRecord: RecipientRecord? = null
|
||||
) {
|
||||
|
||||
/**
|
||||
* @return The common id if all non-null ids are equal, or null if all are null or at least one non-null pair doesn't match.
|
||||
*/
|
||||
val commonId: RecipientId? = findCommonId(listOf(byE164, byPniSid, byPniOnly, byAciSid))
|
||||
val commonId: RecipientId? = findCommonId(listOf(byE164, byPni, byAci))
|
||||
|
||||
/** The ID that would be used to contact this user. */
|
||||
val serviceId: ServiceId? = aci ?: pni
|
||||
|
||||
fun MutableSet<RecipientRecord>.replace(recipientId: RecipientId, update: (RecipientRecord) -> RecipientRecord) {
|
||||
val toUpdate = this.first { it.id == recipientId }
|
||||
@@ -43,7 +46,7 @@ data class PnpDataSet(
|
||||
return this
|
||||
}
|
||||
|
||||
val records: MutableSet<RecipientRecord> = listOfNotNull(e164Record, pniSidRecord, aciSidRecord).toMutableSet()
|
||||
val records: MutableSet<RecipientRecord> = listOfNotNull(e164Record, pniRecord, aciRecord).toMutableSet()
|
||||
|
||||
for (operation in operations) {
|
||||
@Exhaustive
|
||||
@@ -55,16 +58,12 @@ data class PnpDataSet(
|
||||
records.replace(operation.recipientId) { record ->
|
||||
record.copy(
|
||||
pni = null,
|
||||
serviceId = if (record.sidIsPni()) {
|
||||
null
|
||||
} else {
|
||||
record.serviceId
|
||||
}
|
||||
aci = record.aci
|
||||
)
|
||||
}
|
||||
}
|
||||
is PnpOperation.SetAci -> {
|
||||
records.replace(operation.recipientId) { it.copy(serviceId = operation.aci) }
|
||||
records.replace(operation.recipientId) { it.copy(aci = operation.aci) }
|
||||
}
|
||||
is PnpOperation.SetE164 -> {
|
||||
records.replace(operation.recipientId) { it.copy(e164 = operation.e164) }
|
||||
@@ -72,12 +71,7 @@ data class PnpDataSet(
|
||||
is PnpOperation.SetPni -> {
|
||||
records.replace(operation.recipientId) { record ->
|
||||
record.copy(
|
||||
pni = operation.pni,
|
||||
serviceId = if (record.sidIsPni()) {
|
||||
operation.pni
|
||||
} else {
|
||||
record.serviceId ?: operation.pni
|
||||
}
|
||||
pni = operation.pni
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -89,7 +83,7 @@ data class PnpDataSet(
|
||||
primary.copy(
|
||||
e164 = primary.e164 ?: secondary.e164,
|
||||
pni = primary.pni ?: secondary.pni,
|
||||
serviceId = primary.serviceId ?: secondary.serviceId
|
||||
aci = primary.aci ?: secondary.aci
|
||||
)
|
||||
}
|
||||
|
||||
@@ -101,20 +95,16 @@ data class PnpDataSet(
|
||||
}
|
||||
|
||||
val newE164Record = if (e164 != null) records.firstOrNull { it.e164 == e164 } else null
|
||||
val newPniSidRecord = if (pni != null) records.firstOrNull { it.serviceId == pni } else null
|
||||
val newAciSidRecord = if (aci != null) records.firstOrNull { it.serviceId == aci } else null
|
||||
val newPniRecord = if (pni != null) records.firstOrNull { it.pni == pni } else null
|
||||
val newAciRecord = if (aci != null) records.firstOrNull { it.aci == aci } else null
|
||||
|
||||
return PnpDataSet(
|
||||
e164 = e164,
|
||||
pni = pni,
|
||||
aci = aci,
|
||||
return this.copy(
|
||||
byE164 = newE164Record?.id,
|
||||
byPniSid = newPniSidRecord?.id,
|
||||
byPniOnly = byPniOnly,
|
||||
byAciSid = newAciSidRecord?.id,
|
||||
byPni = newPniRecord?.id,
|
||||
byAci = newAciRecord?.id,
|
||||
e164Record = newE164Record,
|
||||
pniSidRecord = newPniSidRecord,
|
||||
aciSidRecord = newAciSidRecord
|
||||
pniRecord = newPniRecord,
|
||||
aciRecord = newAciRecord
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -116,12 +116,20 @@ class SenderKeySharedTable internal constructor(context: Context?, databaseHelpe
|
||||
fun deleteAllFor(recipientId: RecipientId) {
|
||||
val recipient = Recipient.resolved(recipientId)
|
||||
if (recipient.hasServiceId()) {
|
||||
writableDatabase
|
||||
.delete(TABLE_NAME)
|
||||
.where("$ADDRESS = ?", recipient.requireServiceId().toString())
|
||||
.run()
|
||||
if (recipient.hasAci()) {
|
||||
writableDatabase
|
||||
.delete(TABLE_NAME)
|
||||
.where("$ADDRESS = ?", recipient.requireAci().toString())
|
||||
.run()
|
||||
}
|
||||
if (recipient.hasPni()) {
|
||||
writableDatabase
|
||||
.delete(TABLE_NAME)
|
||||
.where("$ADDRESS = ?", recipient.requirePni().toString())
|
||||
.run()
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Recipient doesn't have a UUID! $recipientId")
|
||||
Log.w(TAG, "Recipient doesn't have a ServiceId! $recipientId")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ import org.thoughtcrime.securesms.util.JsonUtils.SaneJSONObject
|
||||
import org.thoughtcrime.securesms.util.LRUCache
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.isScheduled
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.storage.SignalAccountRecord
|
||||
import org.whispersystems.signalservice.api.storage.SignalAccountRecord.PinnedConversation
|
||||
import org.whispersystems.signalservice.api.storage.SignalContactRecord
|
||||
@@ -1700,7 +1699,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
if (threadRecipient.isPushV2Group) {
|
||||
val inviteAddState = record.gv2AddInviteState
|
||||
if (inviteAddState != null) {
|
||||
val from = RecipientId.from(ServiceId.from(inviteAddState.addedOrInvitedBy))
|
||||
val from = RecipientId.from(inviteAddState.addedOrInvitedBy)
|
||||
return if (inviteAddState.isInvited) {
|
||||
Log.i(TAG, "GV2 invite message request from $from")
|
||||
Extra.forGroupV2invite(from, authorId)
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V196_BackCallLinksW
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V197_DropAvatarColorFromCallLinks
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V198_AddMacDigestColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V199_AddThreadActiveColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V200_ResetPniColumn
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
@@ -63,7 +64,7 @@ object SignalDatabaseMigrations {
|
||||
|
||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||
|
||||
const val DATABASE_VERSION = 199
|
||||
const val DATABASE_VERSION = 200
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@@ -270,6 +271,10 @@ object SignalDatabaseMigrations {
|
||||
if (oldVersion < 199) {
|
||||
V199_AddThreadActiveColumn.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 200) {
|
||||
V200_ResetPniColumn.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -47,8 +47,8 @@ import org.thoughtcrime.securesms.util.FileUtils
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||
import org.thoughtcrime.securesms.util.Triple
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.api.push.ACI
|
||||
import org.whispersystems.signalservice.api.push.DistributionId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import java.io.File
|
||||
import java.util.LinkedList
|
||||
import java.util.Locale
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.signal.core.util.requireString
|
||||
import org.thoughtcrime.securesms.database.KeyValueDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.whispersystems.signalservice.api.push.ACI
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
|
||||
/**
|
||||
* This is a combination of the edit message and message recipient migrations (would have been V185 and v186), but as they
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.signal.core.util.requireString
|
||||
import org.thoughtcrime.securesms.database.KeyValueDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.whispersystems.signalservice.api.push.ACI
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
|
||||
/**
|
||||
* This is a fix for a bad situation that could happen during [V185_MessageRecipientsAndEditMessageMigration].
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* This updates the PNI column to have the proper serialized format.
|
||||
*/
|
||||
@Suppress("ClassName")
|
||||
object V200_ResetPniColumn : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("UPDATE recipient SET pni = 'PNI:' || pni WHERE pni NOT NULL")
|
||||
db.execSQL("ALTER TABLE recipient RENAME COLUMN uuid to aci")
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -31,7 +31,7 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.Spannabl
|
||||
private final ACI selfAci;
|
||||
|
||||
public GroupCallUpdateMessageFactory(@NonNull Context context,
|
||||
@NonNull List<ServiceId> joinedMembers,
|
||||
@NonNull List<ACI> joinedMembers,
|
||||
boolean withTime,
|
||||
@NonNull GroupCallUpdateDetails groupCallUpdateDetails)
|
||||
{
|
||||
|
||||
@@ -176,7 +176,7 @@ class GroupRecord(
|
||||
if (isV2Group) {
|
||||
val serviceId = recipient.serviceId
|
||||
if (serviceId.isPresent) {
|
||||
return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get().uuid())
|
||||
return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get().rawUuid)
|
||||
.isPresent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceIds;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
@@ -72,9 +72,9 @@ final class GroupsV2UpdateMessageProducer {
|
||||
* When the revision of the group is 0, the change is very noisy and only the editor is useful.
|
||||
*/
|
||||
UpdateDescription describeNewGroup(@NonNull DecryptedGroup group, @NonNull DecryptedGroupChange decryptedGroupChange) {
|
||||
Optional<DecryptedPendingMember> selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getAci().uuid());
|
||||
Optional<DecryptedPendingMember> selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getAci().getRawUuid());
|
||||
if (!selfPending.isPresent() && selfIds.getPni() != null) {
|
||||
selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getPni().uuid());
|
||||
selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getPni().getRawUuid());
|
||||
}
|
||||
|
||||
if (selfPending.isPresent()) {
|
||||
@@ -90,8 +90,8 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
}
|
||||
|
||||
if (DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getAci().uuid()).isPresent() ||
|
||||
(selfIds.getPni() != null && DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getPni().uuid()).isPresent()))
|
||||
if (DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getAci().getRawUuid()).isPresent() ||
|
||||
(selfIds.getPni() != null && DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfIds.getPni().getRawUuid()).isPresent()))
|
||||
{
|
||||
return updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16);
|
||||
} else {
|
||||
@@ -820,11 +820,11 @@ final class GroupsV2UpdateMessageProducer {
|
||||
@NonNull ByteString uuid1Bytes,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ServiceId serviceId = ServiceId.fromByteStringOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(serviceId);
|
||||
ACI aci = ACI.parseOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(aci);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Collections.singletonList(serviceId),
|
||||
Collections.singletonList(aci),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Collections.singletonList(recipientId);
|
||||
String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, null));
|
||||
@@ -839,14 +839,14 @@ final class GroupsV2UpdateMessageProducer {
|
||||
@NonNull ByteString uuid2Bytes,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ServiceId sid1 = ServiceId.fromByteStringOrUnknown(uuid1Bytes);
|
||||
ServiceId sid2 = ServiceId.fromByteStringOrUnknown(uuid2Bytes);
|
||||
ACI aci1 = ACI.parseOrUnknown(uuid1Bytes);
|
||||
ACI aci2 = ACI.parseOrUnknown(uuid2Bytes);
|
||||
|
||||
RecipientId recipientId1 = RecipientId.from(sid1);
|
||||
RecipientId recipientId2 = RecipientId.from(sid2);
|
||||
RecipientId recipientId1 = RecipientId.from(aci1);
|
||||
RecipientId recipientId2 = RecipientId.from(aci2);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Arrays.asList(sid1, sid2),
|
||||
Arrays.asList(aci1, aci2),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Arrays.asList(recipientId1, recipientId2);
|
||||
String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, null));
|
||||
@@ -862,11 +862,11 @@ final class GroupsV2UpdateMessageProducer {
|
||||
@NonNull Object formatArg,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ServiceId serviceId = ServiceId.fromByteStringOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(serviceId);
|
||||
ACI aci = ACI.parseOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(aci);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Collections.singletonList(serviceId),
|
||||
Collections.singletonList(aci),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Collections.singletonList(recipientId);
|
||||
String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, Collections.singletonList(formatArg)));
|
||||
@@ -883,11 +883,11 @@ final class GroupsV2UpdateMessageProducer {
|
||||
@NonNull Object formatArg,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ServiceId serviceId = ServiceId.fromByteStringOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(serviceId);
|
||||
ACI aci = ACI.parseOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(aci);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Collections.singletonList(serviceId),
|
||||
Collections.singletonList(aci),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Collections.singletonList(recipientId);
|
||||
String templateString = context.getResources().getQuantityString(stringRes, quantity, makePlaceholders(recipientIdList, Collections.singletonList(formatArg)));
|
||||
|
||||
@@ -64,6 +64,7 @@ import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
@@ -307,7 +308,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
|
||||
private static boolean selfCreatedGroup(@NonNull DecryptedGroupChange change) {
|
||||
return change.getRevision() == 0 &&
|
||||
change.getEditor().equals(UuidUtil.toByteString(SignalStore.account().requireAci().uuid()));
|
||||
change.getEditor().equals(UuidUtil.toByteString(SignalStore.account().requireAci().getRawUuid()));
|
||||
}
|
||||
|
||||
public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull String body, @Nullable Consumer<RecipientId> recipientClickHandler) {
|
||||
@@ -345,13 +346,13 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
}
|
||||
|
||||
DecryptedGroup groupState = decryptedGroupV2Context.getGroupState();
|
||||
boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), SignalStore.account().requireAci().uuid()).isPresent();
|
||||
boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), SignalStore.account().requireAci().getRawUuid()).isPresent();
|
||||
|
||||
if (decryptedGroupV2Context.hasChange()) {
|
||||
UUID changeEditor = UuidUtil.fromByteStringOrNull(decryptedGroupV2Context.getChange().getEditor());
|
||||
|
||||
if (changeEditor != null) {
|
||||
return new InviteAddState(invited, changeEditor);
|
||||
return new InviteAddState(invited, ACI.from(changeEditor));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +368,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
@NonNull Function<Recipient, String> stringGenerator,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
return UpdateDescription.mentioning(Collections.singletonList(recipient.getServiceId().orElse(ServiceId.UNKNOWN)),
|
||||
return UpdateDescription.mentioning(Collections.singletonList(recipient.getAci().orElse(ACI.UNKNOWN)),
|
||||
() -> new SpannableString(stringGenerator.apply(recipient.resolve())),
|
||||
iconResource);
|
||||
}
|
||||
@@ -435,10 +436,10 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) {
|
||||
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body);
|
||||
|
||||
List<ServiceId> joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList())
|
||||
List<ACI> joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList())
|
||||
.map(UuidUtil::parseOrNull)
|
||||
.withoutNulls()
|
||||
.map(ServiceId::from)
|
||||
.map(ACI::from)
|
||||
.toList();
|
||||
|
||||
UpdateDescription.SpannableFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails);
|
||||
@@ -467,7 +468,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isGroupV2JoinRequest(UuidUtil.toByteString(serviceId.uuid()));
|
||||
return isGroupV2JoinRequest(UuidUtil.toByteString(serviceId.getRawUuid()));
|
||||
}
|
||||
|
||||
public boolean isGroupV2JoinRequest(@NonNull ByteString uuid) {
|
||||
@@ -489,7 +490,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
DecryptedGroupChange change = decryptedGroupV2Context.getChange();
|
||||
return change.getNewRequestingMembersCount() > 0 &&
|
||||
change.getDeleteRequestingMembersCount() > 0 &&
|
||||
(serviceId == null || change.getEditor().equals(UuidUtil.toByteString(serviceId.uuid())));
|
||||
(serviceId == null || change.getEditor().equals(UuidUtil.toByteString(serviceId.getRawUuid())));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -748,14 +749,14 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
public static final class InviteAddState {
|
||||
|
||||
private final boolean invited;
|
||||
private final UUID addedOrInvitedBy;
|
||||
private final ACI addedOrInvitedBy;
|
||||
|
||||
public InviteAddState(boolean invited, @NonNull UUID addedOrInvitedBy) {
|
||||
public InviteAddState(boolean invited, @NonNull ACI addedOrInvitedBy) {
|
||||
this.invited = invited;
|
||||
this.addedOrInvitedBy = addedOrInvitedBy;
|
||||
}
|
||||
|
||||
public @NonNull UUID getAddedOrInvitedBy() {
|
||||
public @NonNull ACI getAddedOrInvitedBy() {
|
||||
return addedOrInvitedBy;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@ import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
||||
import org.whispersystems.signalservice.api.push.PNI
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
@@ -28,7 +29,7 @@ import java.util.Optional
|
||||
*/
|
||||
data class RecipientRecord(
|
||||
val id: RecipientId,
|
||||
val serviceId: ServiceId?,
|
||||
val aci: ACI?,
|
||||
val pni: PNI?,
|
||||
val username: String?,
|
||||
val e164: String?,
|
||||
@@ -89,21 +90,23 @@ data class RecipientRecord(
|
||||
}
|
||||
|
||||
fun e164Only(): Boolean {
|
||||
return this.e164 != null && this.serviceId == null
|
||||
return this.e164 != null && this.aci == null
|
||||
}
|
||||
|
||||
fun sidOnly(sid: ServiceId): Boolean {
|
||||
return this.e164 == null && this.serviceId == sid && (this.pni == null || this.pni == sid)
|
||||
fun pniOnly(): Boolean {
|
||||
return this.e164 == null && this.aci == null && this.pni != null
|
||||
}
|
||||
|
||||
fun sidIsPni(): Boolean {
|
||||
return this.serviceId != null && this.pni != null && this.serviceId == this.pni
|
||||
fun aciOnly(): Boolean {
|
||||
return this.e164 == null && this.pni == null && this.aci != null
|
||||
}
|
||||
|
||||
fun pniAndAci(): Boolean {
|
||||
return this.serviceId != null && this.pni != null && this.serviceId != this.pni
|
||||
return this.aci != null && this.pni != null
|
||||
}
|
||||
|
||||
val serviceId: ServiceId? = this.aci ?: this.pni
|
||||
|
||||
/**
|
||||
* A bundle of data that's only necessary when syncing to storage service, not for a
|
||||
* [Recipient].
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -18,6 +19,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Contains a list of people mentioned in an update message and a function to create the update message.
|
||||
@@ -28,14 +30,14 @@ public final class UpdateDescription {
|
||||
Spannable create();
|
||||
}
|
||||
|
||||
private final Collection<ServiceId> mentioned;
|
||||
private final SpannableFactory stringFactory;
|
||||
private final Spannable staticString;
|
||||
private final int lightIconResource;
|
||||
private final int lightTint;
|
||||
private final int darkTint;
|
||||
private final Collection<ACI> mentioned;
|
||||
private final SpannableFactory stringFactory;
|
||||
private final Spannable staticString;
|
||||
private final int lightIconResource;
|
||||
private final int lightTint;
|
||||
private final int darkTint;
|
||||
|
||||
private UpdateDescription(@NonNull Collection<ServiceId> mentioned,
|
||||
private UpdateDescription(@NonNull Collection<ACI> mentioned,
|
||||
@Nullable SpannableFactory stringFactory,
|
||||
@Nullable Spannable staticString,
|
||||
@DrawableRes int iconResource,
|
||||
@@ -60,11 +62,11 @@ public final class UpdateDescription {
|
||||
* @param mentioned UUIDs of recipients that are mentioned in the string.
|
||||
* @param stringFactory The background method for generating the string.
|
||||
*/
|
||||
public static UpdateDescription mentioning(@NonNull Collection<ServiceId> mentioned,
|
||||
public static UpdateDescription mentioning(@NonNull Collection<ACI> mentioned,
|
||||
@NonNull SpannableFactory stringFactory,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
return new UpdateDescription(ServiceId.filterKnown(mentioned),
|
||||
return new UpdateDescription(mentioned.stream().filter(ACI::isValid).collect(Collectors.toList()),
|
||||
stringFactory,
|
||||
null,
|
||||
iconResource,
|
||||
@@ -125,7 +127,7 @@ public final class UpdateDescription {
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public @NonNull Collection<ServiceId> getMentioned() {
|
||||
public @NonNull Collection<ACI> getMentioned() {
|
||||
return mentioned;
|
||||
}
|
||||
|
||||
@@ -156,7 +158,7 @@ public final class UpdateDescription {
|
||||
);
|
||||
}
|
||||
|
||||
Set<ServiceId> allMentioned = new HashSet<>();
|
||||
Set<ACI> allMentioned = new HashSet<>();
|
||||
|
||||
for (UpdateDescription updateDescription : updateDescriptions) {
|
||||
allMentioned.addAll(updateDescription.getMentioned());
|
||||
|
||||
Reference in New Issue
Block a user