Use strongly-typed ACIs and PNIs everywhere.

This commit is contained in:
Greyson Parrelli
2023-07-28 12:58:04 -04:00
parent 7ff4a82755
commit 82906aee58
146 changed files with 1416 additions and 1194 deletions

View File

@@ -93,7 +93,7 @@ sealed class CallLogRow {
return FULL
}
if (groupCallUpdateDetails.inCallUuidsList.contains(Recipient.self().requireServiceId().uuid().toString())) {
if (groupCallUpdateDetails.inCallUuidsList.contains(Recipient.self().requireAci().rawUuid.toString())) {
return LOCAL_USER_JOINED
}

View File

@@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
import org.thoughtcrime.securesms.util.DynamicTheme
import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import java.util.Objects
private val TAG: String = Log.tag(ChangeNumberLockActivity::class.java)

View File

@@ -34,8 +34,7 @@ import org.whispersystems.signalservice.api.SvrNoDataException
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest
import org.whispersystems.signalservice.api.account.PreKeyUpload
import org.whispersystems.signalservice.api.kbs.MasterKey
import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import org.whispersystems.signalservice.api.push.ServiceIdType
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity
@@ -243,7 +242,7 @@ class ChangeNumberRepository(
throw AssertionError("No change number metadata")
}
val originalPni = ServiceId.fromByteString(metadata.previousPni)
val originalPni = PNI.parseOrThrow(metadata.previousPni)
if (originalPni == pni) {
Log.i(TAG, "No change has occurred, PNI is unchanged: $pni")

View File

@@ -27,7 +27,7 @@ import org.thoughtcrime.securesms.registration.viewmodel.BaseRegistrationViewMod
import org.thoughtcrime.securesms.registration.viewmodel.NumberViewState
import org.thoughtcrime.securesms.registration.viewmodel.SvrAuthCredentialSet
import org.thoughtcrime.securesms.util.DefaultValueLiveData
import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import org.whispersystems.signalservice.api.push.exceptions.IncorrectCodeException
import org.whispersystems.signalservice.internal.ServiceResponse
import java.util.Objects

View File

@@ -8,7 +8,6 @@ package org.thoughtcrime.securesms.components.settings.app.internal.search
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable
@@ -46,7 +45,7 @@ class InternalSearchViewModel : ViewModel() {
InternalSearchResult(
id = record.id,
name = record.displayName(),
aci = record.serviceId?.toString(),
aci = record.aci?.toString(),
pni = record.pni.toString(),
groupId = record.groupId
)

View File

@@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.UsernameUtil
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException
import java.io.IOException

View File

@@ -165,8 +165,11 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
.setTitle("Are you sure?")
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
.setPositiveButton(android.R.string.ok) { _, _ ->
if (recipient.hasServiceId()) {
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireServiceId().toString())
if (recipient.hasAci()) {
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireAci().toString())
}
if (recipient.hasPni()) {
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requirePni().toString())
}
}
.show()
@@ -182,14 +185,25 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
.setTitle("Are you sure?")
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
.setPositiveButton(android.R.string.ok) { _, _ ->
SignalDatabase.threads.deleteConversation(SignalDatabase.threads.getThreadIdIfExistsFor(recipient.id))
if (recipient.hasServiceId()) {
SignalDatabase.recipients.debugClearServiceIds(recipient.id)
SignalDatabase.recipients.debugClearProfileData(recipient.id)
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireServiceId().toString())
ApplicationDependencies.getProtocolStore().aci().identities().delete(recipient.requireServiceId().toString())
ApplicationDependencies.getProtocolStore().pni().identities().delete(recipient.requireServiceId().toString())
SignalDatabase.threads.deleteConversation(SignalDatabase.threads.getThreadIdIfExistsFor(recipient.id))
}
if (recipient.hasAci()) {
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requireAci().toString())
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requirePni(), addressName = recipient.requireAci().toString())
ApplicationDependencies.getProtocolStore().aci().identities().delete(recipient.requireAci().toString())
}
if (recipient.hasPni()) {
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requireAci(), addressName = recipient.requirePni().toString())
SignalDatabase.sessions.deleteAllFor(serviceId = SignalStore.account().requirePni(), addressName = recipient.requirePni().toString())
ApplicationDependencies.getProtocolStore().aci().identities().delete(recipient.requirePni().toString())
}
startActivity(MainActivity.clearTop(requireContext()))
}
.show()
@@ -237,7 +251,7 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
SignalDatabase.recipients.debugClearE164AndPni(recipient.id)
val splitRecipientId: RecipientId = if (FeatureFlags.phoneNumberPrivacy()) {
SignalDatabase.recipients.getAndPossiblyMergePnpVerified(recipient.pni.orElse(null), recipient.pni.orElse(null), recipient.requireE164())
SignalDatabase.recipients.getAndPossiblyMergePnpVerified(null, recipient.pni.orElse(null), recipient.requireE164())
} else {
SignalDatabase.recipients.getAndPossiblyMerge(recipient.pni.orElse(null), recipient.requireE164())
}
@@ -281,7 +295,7 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
SignalDatabase.recipients.debugRemoveAci(recipient.id)
val aciRecipientId: RecipientId = SignalDatabase.recipients.getAndPossiblyMergePnpVerified(recipient.requireServiceId(), null, null)
val aciRecipientId: RecipientId = SignalDatabase.recipients.getAndPossiblyMergePnpVerified(recipient.requireAci(), null, null)
recipient.profileKey?.let { profileKey ->
SignalDatabase.recipients.setProfileKey(aciRecipientId, ProfileKey(profileKey))

View File

@@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.FeatureFlags
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidTokenException
import org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhaustedException
import org.whispersystems.signalservice.api.services.CdsiV2Service

View File

@@ -4,7 +4,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.util.Arrays;
import java.util.Collection;

View File

@@ -50,7 +50,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.util.Collection;
import java.util.Locale;
@@ -315,7 +315,7 @@ public final class ConversationUpdateItem extends FrameLayout
liveBannedMembers = liveGroup.getBannedMembers();
liveFullMembers = Transformations.map(liveGroup.getFullMembers(),
members -> members.stream()
.map(m -> m.getMember().requireServiceId().uuid())
.map(m -> m.getMember().requireAci().getRawUuid())
.collect(Collectors.toSet()));
liveIsSelfAdmin.observe(lifecycleOwner, updater);
@@ -343,7 +343,7 @@ public final class ConversationUpdateItem extends FrameLayout
Set<UUID> bannedMembers = liveBannedMembers.getValue();
if (bannedMembers != null) {
return recipient.getServiceId().isPresent() && bannedMembers.contains(recipient.requireServiceId().uuid());
return recipient.getServiceId().isPresent() && bannedMembers.contains(recipient.requireServiceId().getRawUuid());
}
return false;
}
@@ -355,7 +355,7 @@ public final class ConversationUpdateItem extends FrameLayout
Set<UUID> members = liveFullMembers.getValue();
if (members != null) {
return recipient.getServiceId().isPresent() && members.contains(recipient.requireServiceId().uuid());
return recipient.hasAci() && members.contains(recipient.requireAci().getRawUuid());
}
return false;
}
@@ -446,12 +446,12 @@ public final class ConversationUpdateItem extends FrameLayout
}
});
} else if (conversationMessage.getMessageRecord().isGroupCall()) {
UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true);
Collection<ServiceId> sids = updateDescription.getMentioned();
UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true);
Collection<ACI> acis = updateDescription.getMentioned();
int text = 0;
if (Util.hasItems(sids)) {
if (sids.contains(SignalStore.account().requireAci())) {
if (Util.hasItems(acis)) {
if (acis.contains(SignalStore.account().requireAci())) {
text = R.string.ConversationUpdateItem_return_to_call;
} else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).getIsCallFull()) {
text = R.string.ConversationUpdateItem_call_is_full;

View File

@@ -176,7 +176,7 @@ public final class SafetyNumberChangeRepository {
Log.d(TAG, "Saving identity result: " + result);
if (result == SignalIdentityKeyStore.SaveResult.NO_CHANGE) {
Log.i(TAG, "Archiving sessions explicitly as they appear to be out of sync.");
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(changedRecipient.getRecipient().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSessions(changedRecipient.getRecipient().getId(), SignalServiceAddress.DEFAULT_DEVICE_ID);
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSiblingSessions(mismatchAddress);
SignalDatabase.senderKeyShared().deleteAllFor(changedRecipient.getRecipient().getId());
}

View File

@@ -69,8 +69,8 @@ public class SignalBaseIdentityKeyStore {
public @NonNull SaveResult saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
IdentityStoreRecord identityRecord = cache.get(address.getName());
RecipientId recipientId = RecipientId.fromSidOrE164(address.getName());
IdentityStoreRecord identityRecord = cache.get(address.getName());
RecipientId recipientId = RecipientId.fromSidOrE164(address.getName());
if (identityRecord == null) {
Log.i(TAG, "Saving new identity for " + address);

View File

@@ -6,7 +6,6 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.message.CiphertextMessage;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
import org.thoughtcrime.securesms.database.SessionTable;
@@ -126,13 +125,23 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
}
}
}
public void archiveSession(@NonNull ServiceId serviceId, int deviceId) {
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
archiveSession(new SignalProtocolAddress(serviceId.toString(), deviceId));
}
}
public void archiveSession(@NonNull RecipientId recipientId, int deviceId) {
public void archiveSessions(@NonNull RecipientId recipientId, int deviceId) {
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasServiceId()) {
archiveSession(new SignalProtocolAddress(recipient.requireServiceId().toString(), deviceId));
if (recipient.hasAci()) {
archiveSession(new SignalProtocolAddress(recipient.requireAci().toString(), deviceId));
}
if (recipient.hasPni()) {
archiveSession(new SignalProtocolAddress(recipient.requirePni().toString(), deviceId));
}
if (recipient.hasE164()) {

View File

@@ -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)
}

View File

@@ -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.")

View File

@@ -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()

View File

@@ -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())

View File

@@ -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

View File

@@ -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
)
}

View File

@@ -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")
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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].

View File

@@ -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")
}
}

View File

@@ -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)
{

View File

@@ -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
}
}

View File

@@ -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)));

View File

@@ -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;
}

View File

@@ -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].

View File

@@ -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());

View File

@@ -85,8 +85,8 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.SignalWebSocket;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.services.CallLinksService;
import org.whispersystems.signalservice.api.services.DonationsService;
import org.whispersystems.signalservice.api.services.ProfileService;

View File

@@ -319,13 +319,13 @@ public final class GroupManager {
GroupTable.V2GroupProperties groupProperties = SignalDatabase.groups().requireGroup(groupId).requireV2GroupProperties();
Recipient recipient = Recipient.resolved(recipientId);
if (groupProperties.getBannedMembers().contains(recipient.requireServiceId().uuid())) {
if (groupProperties.getBannedMembers().contains(recipient.requireServiceId().getRawUuid())) {
Log.i(TAG, "Attempt to ban already banned recipient: " + recipientId);
return;
}
try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) {
editor.ban(recipient.requireServiceId().uuid());
editor.ban(recipient.requireServiceId().getRawUuid());
}
}
@@ -336,7 +336,7 @@ public final class GroupManager {
throws GroupChangeBusyException, IOException, GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException
{
try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) {
editor.unban(Collections.singleton(Recipient.resolved(recipientId).requireServiceId().uuid()));
editor.unban(Collections.singleton(Recipient.resolved(recipientId).requireServiceId().getRawUuid()));
}
}

View File

@@ -64,8 +64,8 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException;
import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceIds;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
@@ -176,7 +176,7 @@ final class GroupManagerV2 {
Map<UUID, UuidCiphertext> uuidCipherTexts = new HashMap<>();
for (Recipient recipient : recipients) {
uuidCipherTexts.put(recipient.requireServiceId().uuid(), clientZkGroupCipher.encryptUuid(recipient.requireServiceId().uuid()));
uuidCipherTexts.put(recipient.requireServiceId().getRawUuid(), clientZkGroupCipher.encryptUuid(recipient.requireServiceId().getRawUuid()));
}
return uuidCipherTexts;
@@ -231,7 +231,7 @@ final class GroupManagerV2 {
return latest;
}
Optional<DecryptedMember> selfInFullMemberList = DecryptedGroupUtil.findMemberByUuid(latest.getMembersList(), selfAci.uuid());
Optional<DecryptedMember> selfInFullMemberList = DecryptedGroupUtil.findMemberByUuid(latest.getMembersList(), selfAci.getRawUuid());
if (!selfInFullMemberList.isPresent()) {
return latest;
@@ -356,7 +356,7 @@ final class GroupManagerV2 {
groupCandidates = GroupCandidate.withoutExpiringProfileKeyCredentials(groupCandidates);
}
return commitChangeWithConflictResolution(selfAci, groupOperations.createModifyGroupMembershipChange(groupCandidates, bannedMembers, selfAci.uuid()));
return commitChangeWithConflictResolution(selfAci, groupOperations.createModifyGroupMembershipChange(groupCandidates, bannedMembers, selfAci.getRawUuid()));
}
@WorkerThread
@@ -431,7 +431,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
Set<UUID> uuids = Stream.of(recipientIds)
.map(r -> Recipient.resolved(r).requireServiceId().uuid())
.map(r -> Recipient.resolved(r).requireServiceId().getRawUuid())
.collect(Collectors.toSet());
return commitChangeWithConflictResolution(selfAci, groupOperations.createApproveGroupJoinRequest(uuids));
@@ -442,7 +442,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
Set<UUID> uuids = Stream.of(recipientIds)
.map(r -> Recipient.resolved(r).requireServiceId().uuid())
.map(r -> Recipient.resolved(r).requireServiceId().getRawUuid())
.collect(Collectors.toSet());
return commitChangeWithConflictResolution(selfAci, groupOperations.createRefuseGroupJoinRequest(uuids, true, v2GroupProperties.getDecryptedGroup().getBannedMembersList()));
@@ -454,7 +454,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
Recipient recipient = Recipient.resolved(recipientId);
return commitChangeWithConflictResolution(selfAci, groupOperations.createChangeMemberRole(recipient.requireServiceId().uuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
return commitChangeWithConflictResolution(selfAci, groupOperations.createChangeMemberRole(recipient.requireServiceId().getRawUuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
}
@WorkerThread
@@ -463,9 +463,9 @@ final class GroupManagerV2 {
{
GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
DecryptedGroup decryptedGroup = groupRecord.requireV2GroupProperties().getDecryptedGroup();
Optional<DecryptedMember> selfMember = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), selfAci.uuid());
Optional<DecryptedPendingMember> aciPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfAci.uuid());
Optional<DecryptedPendingMember> pniPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfPni.uuid());
Optional<DecryptedMember> selfMember = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), selfAci.getRawUuid());
Optional<DecryptedPendingMember> aciPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfAci.getRawUuid());
Optional<DecryptedPendingMember> pniPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfPni.getRawUuid());
Optional<DecryptedPendingMember> selfPendingMember = Optional.empty();
ServiceId serviceId = selfAci;
@@ -494,7 +494,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
return commitChangeWithConflictResolution(selfAci,
groupOperations.createRemoveMembersChange(Collections.singleton(serviceId.uuid()),
groupOperations.createRemoveMembersChange(Collections.singleton(serviceId.getRawUuid()),
ban,
ban ? v2GroupProperties.getDecryptedGroup().getBannedMembersList()
: Collections.emptyList()),
@@ -506,9 +506,9 @@ final class GroupManagerV2 {
@NonNull GroupManager.GroupActionResult addMemberAdminsAndLeaveGroup(Collection<RecipientId> newAdmins)
throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException
{
List<UUID> newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).requireServiceId().uuid()).toList();
List<UUID> newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).requireServiceId().getRawUuid()).toList();
return commitChangeWithConflictResolution(selfAci, groupOperations.createLeaveAndPromoteMembersToAdmin(selfAci.uuid(),
return commitChangeWithConflictResolution(selfAci, groupOperations.createLeaveAndPromoteMembersToAdmin(selfAci.getRawUuid(),
newAdminRecipients));
}
@@ -518,7 +518,7 @@ final class GroupManagerV2 {
{
ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey();
DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup();
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.uuid());
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.getRawUuid());
if (!selfInGroup.isPresent()) {
Log.w(TAG, "Self not in group " + groupId);
@@ -548,15 +548,15 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup();
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.uuid());
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.getRawUuid());
if (selfInGroup.isPresent()) {
Log.w(TAG, "Self already in group");
return null;
}
Optional<DecryptedPendingMember> aciInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfAci.uuid());
Optional<DecryptedPendingMember> pniInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfPni.uuid());
Optional<DecryptedPendingMember> aciInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfAci.getRawUuid());
Optional<DecryptedPendingMember> pniInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfPni.getRawUuid());
GroupCandidate groupCandidate = groupCandidateHelper.recipientIdToCandidate(Recipient.self().getId());
@@ -650,7 +650,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException
{
boolean refetchedAddMemberCredentials = false;
change.setSourceUuid(UuidUtil.toByteString(authServiceId.uuid()));
change.setSourceUuid(UuidUtil.toByteString(authServiceId.getRawUuid()));
for (int attempt = 0; attempt < 5; attempt++) {
try {
@@ -704,7 +704,7 @@ final class GroupManagerV2 {
GroupChange.Actions changeActions = change.build();
return GroupChangeUtil.resolveConflict(groupUpdateResult.getLatestServer(),
groupOperations.decryptChange(changeActions, authServiceId.uuid()),
groupOperations.decryptChange(changeActions, authServiceId.getRawUuid()),
changeActions);
} catch (VerificationFailedException | InvalidGroupStateException ex) {
throw new GroupChangeFailedException(ex);
@@ -1203,7 +1203,7 @@ final class GroupManagerV2 {
void cancelJoinRequest()
throws GroupChangeFailedException, IOException
{
Set<UUID> uuids = Collections.singleton(selfAci.uuid());
Set<UUID> uuids = Collections.singleton(selfAci.getRawUuid());
GroupChange signedGroupChange;
try {
@@ -1331,8 +1331,9 @@ final class GroupManagerV2 {
}
private static @NonNull List<RecipientId> getPendingMemberRecipientIds(@NonNull List<DecryptedPendingMember> newPendingMembersList) {
// TODO [greyson][ServiceId] Pending members can be ACI's or PNI's
return Stream.of(DecryptedGroupUtil.pendingToUuidList(newPendingMembersList))
.map(uuid -> RecipientId.from(ServiceId.from(uuid)))
.map(uuid -> RecipientId.from(ACI.from(uuid)))
.toList();
}

View File

@@ -80,12 +80,12 @@ public final class GroupProtoUtil {
@WorkerThread
public static Recipient pendingMemberToRecipient(@NonNull Context context, @NonNull DecryptedPendingMember pendingMember) {
return uuidByteStringToRecipient(context, pendingMember.getUuid());
return pendingMemberServiceIdToRecipient(context, pendingMember.getUuid());
}
@WorkerThread
public static Recipient uuidByteStringToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) {
ServiceId serviceId = ServiceId.fromByteString(uuidByteString);
public static Recipient pendingMemberServiceIdToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) {
ServiceId serviceId = ServiceId.parseOrThrow(uuidByteString);
if (serviceId.isUnknown()) {
return Recipient.UNKNOWN;
@@ -96,7 +96,7 @@ public final class GroupProtoUtil {
@WorkerThread
public static @NonNull RecipientId uuidByteStringToRecipientId(@NonNull ByteString uuidByteString) {
ServiceId serviceId = ServiceId.fromByteString(uuidByteString);
ServiceId serviceId = ServiceId.parseOrThrow(uuidByteString);
if (serviceId.isUnknown()) {
return RecipientId.UNKNOWN;

View File

@@ -4,7 +4,6 @@ import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.zkgroup.GenericServerPublicParams;
import org.signal.libsignal.zkgroup.GenericServerSecretParams;
import org.signal.libsignal.zkgroup.VerificationFailedException;
import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPniResponse;
import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredential;
@@ -12,9 +11,6 @@ import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredentialPresentation
import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredentialResponse;
import org.signal.libsignal.zkgroup.calllinks.CallLinkSecretParams;
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2AuthorizationString;
@@ -130,13 +126,13 @@ public class GroupsV2Authorization {
}
CallLinkAuthCredential credential = authCredentialResponse.receive(
Recipient.self().requireServiceId().uuid(),
Recipient.self().requireServiceId().getRawUuid(),
Instant.ofEpochSecond(todaySeconds),
genericServerPublicParams
);
return credential.present(
Recipient.self().requireServiceId().uuid(),
Recipient.self().requireServiceId().getRawUuid(),
Instant.ofEpochSecond(todaySeconds),
genericServerPublicParams,
callLinkSecretParams

View File

@@ -111,7 +111,7 @@ public final class LiveGroup {
return Stream.of(requestingMembersList)
.map(requestingMember -> {
Recipient recipient = Recipient.externalPush(ServiceId.fromByteString(requestingMember.getUuid()));
Recipient recipient = Recipient.externalPush(ServiceId.parseOrThrow(requestingMember.getUuid()));
return new GroupMemberEntry.RequestingMember(recipient, selfAdmin);
})
.toList();

View File

@@ -77,7 +77,7 @@ final class PendingMemberInvitesRepository {
}
}
} else {
Recipient inviter = GroupProtoUtil.uuidByteStringToRecipient(context, inviterUuid);
Recipient inviter = GroupProtoUtil.pendingMemberServiceIdToRecipient(context, inviterUuid);
ArrayList<UuidCiphertext> uuidCipherTexts = new ArrayList<>(invitedMembers.size());
for (DecryptedPendingMember pendingMember : invitedMembers) {

View File

@@ -51,7 +51,7 @@ public class GroupCandidateHelper {
}
Optional<ExpiringProfileKeyCredential> expiringProfileKeyCredential = Optional.ofNullable(recipient.getExpiringProfileKeyCredential());
GroupCandidate candidate = new GroupCandidate(serviceId.uuid(), expiringProfileKeyCredential);
GroupCandidate candidate = new GroupCandidate(serviceId.getRawUuid(), expiringProfileKeyCredential);
if (!candidate.hasValidProfileKeyCredential()) {
recipientTable.clearProfileKeyCredential(recipient.getId());

View File

@@ -12,6 +12,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.protos.groups.local.DecryptedMember;
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil;
@@ -97,11 +98,11 @@ public final class ProfileKeySet {
}
if (memberUuid.equals(changeSource)) {
authoritativeProfileKeys.put(ServiceId.from(memberUuid), profileKey);
profileKeys.remove(ServiceId.from(memberUuid));
authoritativeProfileKeys.put(ACI.from(memberUuid), profileKey);
profileKeys.remove(ACI.from(memberUuid));
} else {
if (!authoritativeProfileKeys.containsKey(ServiceId.from(memberUuid))) {
profileKeys.put(ServiceId.from(memberUuid), profileKey);
if (!authoritativeProfileKeys.containsKey(ACI.from(memberUuid))) {
profileKeys.put(ACI.from(memberUuid), profileKey);
}
}
}

View File

@@ -55,7 +55,7 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException;
import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException;
import org.whispersystems.signalservice.api.groupsv2.PartialDecryptedGroup;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceIds;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.exceptions.GroupNotFoundException;
@@ -171,13 +171,13 @@ public class GroupsV2StateProcessor {
}
private StateProcessorForGroup(@NonNull ServiceIds serviceIds,
@NonNull Context context,
@NonNull GroupTable groupDatabase,
@NonNull GroupsV2Api groupsV2Api,
@NonNull GroupsV2Authorization groupsV2Authorization,
@NonNull GroupMasterKey groupMasterKey,
@NonNull GroupSecretParams groupSecretParams,
@NonNull RecipientTable recipientTable)
@NonNull Context context,
@NonNull GroupTable groupDatabase,
@NonNull GroupsV2Api groupsV2Api,
@NonNull GroupsV2Authorization groupsV2Authorization,
@NonNull GroupMasterKey groupMasterKey,
@NonNull GroupSecretParams groupSecretParams,
@NonNull RecipientTable recipientTable)
{
this.serviceIds = serviceIds;
this.context = context;
@@ -425,23 +425,23 @@ public class GroupsV2StateProcessor {
throw new IOException(e);
}
if (localState != null && localState.getRevision() >= latestServerGroup.getRevision() && GroupProtoUtil.isMember(serviceIds.getAci().uuid(), localState.getMembersList())) {
if (localState != null && localState.getRevision() >= latestServerGroup.getRevision() && GroupProtoUtil.isMember(serviceIds.getAci().getRawUuid(), localState.getMembersList())) {
info("Local state is at or later than server");
return new GroupUpdateResult(GroupState.GROUP_CONSISTENT_OR_AHEAD, null);
}
if (latestRevisionOnly || !GroupProtoUtil.isMember(serviceIds.getAci().uuid(), latestServerGroup.getMembersList())) {
if (latestRevisionOnly || !GroupProtoUtil.isMember(serviceIds.getAci().getRawUuid(), latestServerGroup.getMembersList())) {
info("Latest revision or not a member, use latest only");
inputGroupState = new GlobalGroupState(localState, Collections.singletonList(new ServerGroupLogEntry(latestServerGroup.getFullyDecryptedGroup(), null)));
} else {
int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, serviceIds.getAci().uuid());
int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, serviceIds.getAci().getRawUuid());
int logsNeededFrom = localState != null ? Math.max(localState.getRevision(), revisionWeWereAdded) : revisionWeWereAdded;
boolean includeFirstState = forceIncludeFirst ||
localState == null ||
localState.getRevision() < 0 ||
localState.getRevision() == revisionWeWereAdded ||
!GroupProtoUtil.isMember(serviceIds.getAci().uuid(), localState.getMembersList()) ||
!GroupProtoUtil.isMember(serviceIds.getAci().getRawUuid(), localState.getMembersList()) ||
(revision == LATEST && localState.getRevision() + 1 < latestServerGroup.getRevision());
info("Requesting from server currentRevision: " + (localState != null ? localState.getRevision() : "null") +
@@ -556,7 +556,7 @@ public class GroupsV2StateProcessor {
}
Recipient groupRecipient = Recipient.externalGroupExact(groupId);
UUID selfUuid = serviceIds.getAci().uuid();
UUID selfUuid = serviceIds.getAci().getRawUuid();
DecryptedGroup decryptedGroup = groupDatabase.requireGroup(groupId)
.requireV2GroupProperties()
@@ -668,17 +668,17 @@ public class GroupsV2StateProcessor {
@VisibleForTesting
static class ProfileAndMessageHelper {
private final Context context;
private final ServiceId serviceId;
private final Context context;
private final ACI aci;
private final GroupId.V2 groupId;
private final RecipientTable recipientTable;
@VisibleForTesting
GroupMasterKey masterKey;
ProfileAndMessageHelper(@NonNull Context context, @NonNull ServiceId serviceId, @NonNull GroupMasterKey masterKey, @NonNull GroupId.V2 groupId, @NonNull RecipientTable recipientTable) {
ProfileAndMessageHelper(@NonNull Context context, @NonNull ACI aci, @NonNull GroupMasterKey masterKey, @NonNull GroupId.V2 groupId, @NonNull RecipientTable recipientTable) {
this.context = context;
this.serviceId = serviceId;
this.aci = aci;
this.masterKey = masterKey;
this.groupId = groupId;
this.recipientTable = recipientTable;
@@ -686,15 +686,15 @@ public class GroupsV2StateProcessor {
void determineProfileSharing(@NonNull GlobalGroupState inputGroupState, @NonNull DecryptedGroup newLocalState) {
if (inputGroupState.getLocalState() != null) {
boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), serviceId.uuid()).isPresent();
boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), aci.getRawUuid()).isPresent();
if (wasAMemberAlready) {
return;
}
}
Optional<DecryptedMember> selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), serviceId.uuid());
Optional<DecryptedPendingMember> selfAsPendingOptional = DecryptedGroupUtil.findPendingByUuid(newLocalState.getPendingMembersList(), serviceId.uuid());
Optional<DecryptedMember> selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), aci.getRawUuid());
Optional<DecryptedPendingMember> selfAsPendingOptional = DecryptedGroupUtil.findPendingByUuid(newLocalState.getPendingMembersList(), aci.getRawUuid());
if (selfAsMemberOptional.isPresent()) {
DecryptedMember selfAsMember = selfAsMemberOptional.get();
@@ -705,7 +705,7 @@ public class GroupsV2StateProcessor {
.filter(c -> c != null && c.getRevision() == revisionJoinedAt)
.findFirst()
.map(c -> Optional.ofNullable(UuidUtil.fromByteStringOrNull(c.getEditor()))
.map(uuid -> Recipient.externalPush(ServiceId.from(uuid))))
.map(uuid -> Recipient.externalPush(ACI.from(uuid))))
.orElse(Optional.empty());
if (addedByOptional.isPresent()) {
@@ -713,7 +713,7 @@ public class GroupsV2StateProcessor {
Log.i(TAG, String.format("Added as a full member of %s by %s", groupId, addedBy.getId()));
if (addedBy.isBlocked() && (inputGroupState.getLocalState() == null || !DecryptedGroupUtil.isRequesting(inputGroupState.getLocalState(), serviceId.uuid()))) {
if (addedBy.isBlocked() && (inputGroupState.getLocalState() == null || !DecryptedGroupUtil.isRequesting(inputGroupState.getLocalState(), aci.getRawUuid()))) {
Log.i(TAG, "Added by a blocked user. Leaving group.");
ApplicationDependencies.getJobManager().add(new LeaveGroupV2Job(groupId));
//noinspection UnnecessaryReturnStatement
@@ -730,7 +730,7 @@ public class GroupsV2StateProcessor {
}
} else if (selfAsPendingOptional.isPresent()) {
Optional<Recipient> addedBy = selfAsPendingOptional.flatMap(adder -> Optional.ofNullable(UuidUtil.fromByteStringOrNull(adder.getAddedByUuid()))
.map(uuid -> Recipient.externalPush(ServiceId.from(uuid))));
.map(uuid -> Recipient.externalPush(ACI.from(uuid))));
if (addedBy.isPresent() && addedBy.get().isBlocked()) {
Log.i(TAG, String.format("Added to group %s by a blocked user %s. Leaving group.", groupId, addedBy.get().getId()));
@@ -795,9 +795,9 @@ public class GroupsV2StateProcessor {
}
void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp) {
Optional<ServiceId> editor = getEditor(decryptedGroupV2Context).map(ServiceId::from);
Optional<ACI> editor = getEditor(decryptedGroupV2Context).map(ACI::from);
boolean outgoing = !editor.isPresent() || serviceId.equals(editor.get());
boolean outgoing = !editor.isPresent() || aci.equals(editor.get());
if (outgoing) {
try {
@@ -835,7 +835,7 @@ public class GroupsV2StateProcessor {
if (changeEditor.isPresent()) {
return changeEditor;
} else {
Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), serviceId.uuid());
Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), aci.getRawUuid());
if (pendingByUuid.isPresent()) {
return Optional.ofNullable(UuidUtil.fromByteStringOrNull(pendingByUuid.get().getAddedByUuid()));
}

View File

@@ -85,7 +85,7 @@ public class AutomaticSessionResetJob extends BaseJob {
@Override
protected void onRun() throws Exception {
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(recipientId, deviceId);
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSessions(recipientId, deviceId);
SignalDatabase.senderKeyShared().deleteAllFor(recipientId);
insertLocalMessage();

View File

@@ -119,7 +119,7 @@ public final class GroupV2UpdateSelfProfileKeyJob extends BaseJob {
continue;
}
ByteString selfUuidBytes = UuidUtil.toByteString(Recipient.self().requireServiceId().uuid());
ByteString selfUuidBytes = UuidUtil.toByteString(Recipient.self().requireAci().getRawUuid());
DecryptedMember selfMember = group.get().requireV2GroupProperties().getDecryptedGroup().getMembersList()
.stream()
.filter(m -> m.getUuid().equals(selfUuidBytes))

View File

@@ -74,7 +74,7 @@ class MultiDeviceStorySendSyncJob private constructor(parameters: Parameters, pr
private fun buildSentTranscript(recipientsSet: Set<SignalServiceStoryMessageRecipient>): SentTranscriptMessage {
return SentTranscriptMessage(
Optional.of(SignalServiceAddress(Recipient.self().requireServiceId())),
Optional.of(SignalServiceAddress(Recipient.self().requireAci())),
sentTimestamp,
Optional.empty(),
0,

View File

@@ -33,7 +33,7 @@ import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.messages.SendMessageResult;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
@@ -77,8 +77,8 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
Set<RecipientId> recipients = Stream.concat(Stream.of(memberUuids), Stream.of(pendingUuids))
.filter(uuid -> !UuidUtil.UNKNOWN_UUID.equals(uuid))
.filter(uuid -> !SignalStore.account().requireAci().uuid().equals(uuid))
.map(uuid -> Recipient.externalPush(ServiceId.from(uuid)))
.filter(uuid -> !SignalStore.account().requireAci().getRawUuid().equals(uuid))
.map(uuid -> Recipient.externalPush(ACI.from(uuid)))
.filter(recipient -> recipient.getRegistered() != RecipientTable.RegisteredState.NOT_REGISTERED)
.map(Recipient::getId)
.collect(Collectors.toSet());

View File

@@ -67,6 +67,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemo
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServicePreview;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException;
@@ -325,7 +326,7 @@ public abstract class PushSendJob extends SendJob {
protected Optional<SignalServiceDataMessage.Quote> getQuoteFor(OutgoingMessage message) throws IOException {
if (message.getOutgoingQuote() == null) return Optional.empty();
if (message.isMessageEdit()) {
return Optional.of(new SignalServiceDataMessage.Quote(0, ServiceId.UNKNOWN, "", null, null, SignalServiceDataMessage.Quote.Type.NORMAL, null));
return Optional.of(new SignalServiceDataMessage.Quote(0, ACI.UNKNOWN, "", null, null, SignalServiceDataMessage.Quote.Type.NORMAL, null));
}
long quoteId = message.getOutgoingQuote().getId();
@@ -383,7 +384,7 @@ public abstract class PushSendJob extends SendJob {
if (quoteAuthorRecipient.isMaybeRegistered()) {
return Optional.of(new SignalServiceDataMessage.Quote(quoteId, RecipientUtil.getOrFetchServiceId(context, quoteAuthorRecipient), quoteBody, quoteAttachments, quoteMentions, quoteType.getDataMessageType(), bodyRanges));
} else if (quoteAuthorRecipient.hasServiceId()) {
return Optional.of(new SignalServiceDataMessage.Quote(quoteId, quoteAuthorRecipient.requireServiceId(), quoteBody, quoteAttachments, quoteMentions, quoteType.getDataMessageType(), bodyRanges));
return Optional.of(new SignalServiceDataMessage.Quote(quoteId, quoteAuthorRecipient.requireAci(), quoteBody, quoteAttachments, quoteMentions, quoteType.getDataMessageType(), bodyRanges));
} else {
return Optional.empty();
}
@@ -451,7 +452,7 @@ public abstract class PushSendJob extends SendJob {
List<SignalServiceDataMessage.Mention> getMentionsFor(@NonNull List<Mention> mentions) {
return Stream.of(mentions)
.map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireServiceId(), m.getStart(), m.getLength()))
.map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireAci(), m.getStart(), m.getLength()))
.toList();
}

View File

@@ -22,8 +22,8 @@ import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.util.Base64
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import org.whispersystems.signalservice.api.push.ServiceIds
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import java.security.SecureRandom
@@ -85,6 +85,12 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
if (!store.containsKey(KEY_ACI_IDENTITY_PUBLIC_KEY)) {
migrateFromSharedPrefsV2(ApplicationDependencies.getApplication())
}
store.getString(KEY_PNI, null)?.let { pni ->
if (!pni.startsWith("PNI:")) {
store.beginWrite().putString(KEY_PNI, "PNI:$pni").commit()
}
}
}
public override fun onFirstEverAppLaunch() = Unit

View File

@@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.VersionTracker;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.util.Arrays;
import java.util.LinkedList;

View File

@@ -42,7 +42,7 @@ object CallMessageProcessor {
handleCallHangupMessage(envelope, metadata, hangup, senderRecipient.id, callMessage.hasLegacyHangup())
}
callMessage.hasBusy() -> handleCallBusyMessage(envelope, metadata, callMessage.busy, senderRecipient.id)
callMessage.hasOpaque() -> handleCallOpaqueMessage(envelope, metadata, callMessage.opaque, senderRecipient.requireServiceId(), serverDeliveredTimestamp)
callMessage.hasOpaque() -> handleCallOpaqueMessage(envelope, metadata, callMessage.opaque, senderRecipient.requireAci(), serverDeliveredTimestamp)
}
}
@@ -146,7 +146,7 @@ object CallMessageProcessor {
ApplicationDependencies.getSignalCallManager()
.receivedOpaqueMessage(
OpaqueMessageMetadata(
senderServiceId.uuid(),
senderServiceId.rawUuid,
opaque.data.toByteArray(),
metadata.sourceDeviceId,
messageAgeSeconds

View File

@@ -95,6 +95,7 @@ import org.thoughtcrime.securesms.util.isStory
import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata
import org.whispersystems.signalservice.api.payments.Money
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.util.OptionalUtil.asOptional
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content
@@ -992,10 +993,10 @@ object DataMessageProcessor {
return mentionBodyRanges
.filter { it.hasMentionAci() }
.mapNotNull {
val serviceId = ServiceId.parseOrNull(it.mentionAci)
val aci = ACI.parseOrNull(it.mentionAci)
if (serviceId != null && !serviceId.isUnknown) {
val id = Recipient.externalPush(serviceId).id
if (aci != null && !aci.isUnknown) {
val id = Recipient.externalPush(aci).id
Mention(id, it.start, it.length)
} else {
null

View File

@@ -537,7 +537,7 @@ public class MessageContentProcessor {
Optional<GroupRecord> groupRecord = groupDatabase.getGroup(groupId);
if (groupRecord.isPresent() && !groupRecord.get().getMembers().contains(senderRecipient.getId())) {
log(String.valueOf(content.getTimestamp()), "Ignoring GV2 message from member not in group " + groupId + ". Sender: " + senderRecipient.getId() + " | " + senderRecipient.requireServiceId());
log(String.valueOf(content.getTimestamp()), "Ignoring GV2 message from member not in group " + groupId + ". Sender: " + senderRecipient.getId() + " | " + senderRecipient.requireAci());
return true;
}
@@ -739,7 +739,7 @@ public class MessageContentProcessor {
}
ApplicationDependencies.getSignalCallManager()
.receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireServiceId().uuid(),
.receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireAci().getRawUuid(),
message.getOpaque(),
content.getSenderDevice(),
messageAgeSeconds));
@@ -843,7 +843,7 @@ public class MessageContentProcessor {
log(content.getTimestamp(), "Unknown group message.");
warn(content.getTimestamp(), "Received a GV2 message for a group we have no knowledge of -- attempting to fix this state.");
ServiceId authServiceId = ServiceId.parseOrNull(content.getDestinationUuid());
ServiceId authServiceId = ServiceId.parseOrNull(content.getDestinationServiceId());
if (authServiceId == null) {
warn(content.getTimestamp(), "Group message missing destination uuid, defaulting to ACI");
authServiceId = SignalStore.account().requireAci();
@@ -1290,7 +1290,7 @@ public class MessageContentProcessor {
return;
}
ServiceId serviceId = ServiceId.fromByteString(callEvent.getConversationId());
ServiceId serviceId = ServiceId.parseOrThrow(callEvent.getConversationId());
RecipientId recipientId = RecipientId.from(serviceId);
log(envelopeTimestamp, "Synchronize call event call: " + callId);
@@ -3061,7 +3061,7 @@ public class MessageContentProcessor {
ratchetKeyMatches(requester, content.getSenderDevice(), decryptionErrorMessage.getRatchetKey().get()))
{
warn(content.getTimestamp(), "[RetryReceipt-I] Ratchet key matches. Archiving the session.");
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.getId(), content.getSenderDevice());
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.requireServiceId(), content.getSenderDevice());
archivedSession = true;
}

View File

@@ -569,7 +569,7 @@ open class MessageContentProcessorV2(private val context: Context) {
ratchetKeyMatches(requester, metadata.sourceDeviceId, decryptionErrorMessage.ratchetKey.get())
) {
warn(envelope.timestamp, "[RetryReceipt-I] Ratchet key matches. Archiving the session.")
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.id, metadata.sourceDeviceId)
ApplicationDependencies.getProtocolStore().aci().sessions().archiveSession(requester.requireServiceId(), metadata.sourceDeviceId)
archivedSession = true
}
@@ -604,7 +604,7 @@ open class MessageContentProcessorV2(private val context: Context) {
}
private fun ratchetKeyMatches(recipient: Recipient, deviceId: Int, ratchetKey: ECPublicKey): Boolean {
val address = recipient.resolve().requireServiceId().toProtocolAddress(deviceId)
val address = recipient.resolve().requireAci().toProtocolAddress(deviceId)
val session = ApplicationDependencies.getProtocolStore().aci().loadSession(address)
return session.currentRatchetKeyMatches(ratchetKey)
}

View File

@@ -55,8 +55,9 @@ import org.whispersystems.signalservice.api.crypto.SignalGroupSessionBuilder
import org.whispersystems.signalservice.api.crypto.SignalServiceCipher
import org.whispersystems.signalservice.api.crypto.SignalServiceCipherResult
import org.whispersystems.signalservice.api.messages.EnvelopeContentValidator
import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope
@@ -158,13 +159,17 @@ object MessageDecryptor {
}
if (FeatureFlags.phoneNumberPrivacy() && cipherResult.content.hasPniSignatureMessage()) {
handlePniSignatureMessage(
envelope,
cipherResult.metadata.sourceServiceId,
cipherResult.metadata.sourceE164,
cipherResult.metadata.sourceDeviceId,
cipherResult.content.pniSignatureMessage
)
if (cipherResult.metadata.sourceServiceId is ACI) {
handlePniSignatureMessage(
envelope,
cipherResult.metadata.sourceServiceId as ACI,
cipherResult.metadata.sourceE164,
cipherResult.metadata.sourceDeviceId,
cipherResult.content.pniSignatureMessage
)
} else {
Log.w(TAG, "${logPrefix(envelope)} Ignoring PNI signature because the sourceServiceId isn't an ACI!")
}
} else if (cipherResult.content.hasPniSignatureMessage()) {
Log.w(TAG, "${logPrefix(envelope)} Ignoring PNI signature because the feature flag is disabled!")
}
@@ -295,37 +300,37 @@ object MessageDecryptor {
SignalGroupSessionBuilder(ReentrantSessionLock.INSTANCE, GroupSessionBuilder(senderKeyStore)).process(sender, message)
}
private fun handlePniSignatureMessage(envelope: Envelope, serviceId: ServiceId, e164: String?, deviceId: Int, pniSignatureMessage: PniSignatureMessage) {
Log.i(TAG, "${logPrefix(envelope, serviceId)} Processing PniSignatureMessage")
private fun handlePniSignatureMessage(envelope: Envelope, aci: ACI, e164: String?, deviceId: Int, pniSignatureMessage: PniSignatureMessage) {
Log.i(TAG, "${logPrefix(envelope, aci)} Processing PniSignatureMessage")
val pni: PNI = PNI.parseOrThrow(pniSignatureMessage.pni.toByteArray())
if (SignalDatabase.recipients.isAssociated(serviceId, pni)) {
Log.i(TAG, "${logPrefix(envelope, serviceId)}[handlePniSignatureMessage] ACI ($serviceId) and PNI ($pni) are already associated.")
if (SignalDatabase.recipients.isAssociated(aci, pni)) {
Log.i(TAG, "${logPrefix(envelope, aci)}[handlePniSignatureMessage] ACI ($aci) and PNI ($pni) are already associated.")
return
}
val identityStore = ApplicationDependencies.getProtocolStore().aci().identities()
val aciAddress = SignalProtocolAddress(serviceId.toString(), deviceId)
val aciAddress = SignalProtocolAddress(aci.toString(), deviceId)
val pniAddress = SignalProtocolAddress(pni.toString(), deviceId)
val aciIdentity = identityStore.getIdentity(aciAddress)
val pniIdentity = identityStore.getIdentity(pniAddress)
if (aciIdentity == null) {
Log.w(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] No identity found for ACI address $aciAddress")
Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for ACI address $aciAddress")
return
}
if (pniIdentity == null) {
Log.w(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] No identity found for PNI address $pniAddress")
Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for PNI address $pniAddress")
return
}
if (pniIdentity.verifyAlternateIdentity(aciIdentity, pniSignatureMessage.signature.toByteArray())) {
Log.i(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] PNI signature is valid. Associating ACI ($serviceId) with PNI ($pni)")
SignalDatabase.recipients.getAndPossiblyMergePnpVerified(serviceId, pni, e164)
Log.i(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] PNI signature is valid. Associating ACI ($aci) with PNI ($pni)")
SignalDatabase.recipients.getAndPossiblyMergePnpVerified(aci, pni, e164)
} else {
Log.w(TAG, "${logPrefix(envelope, serviceId)}[validatePniSignature] Invalid PNI signature! Cannot associate ACI ($serviceId) with PNI ($pni)")
Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] Invalid PNI signature! Cannot associate ACI ($aci) with PNI ($pni)")
}
}

View File

@@ -98,6 +98,7 @@ import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer
import org.whispersystems.signalservice.api.push.DistributionId
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.storage.StorageKey
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
@@ -1227,8 +1228,8 @@ object SyncMessageProcessor {
return
}
val serviceId = ServiceId.fromByteString(callEvent.conversationId)
val recipientId = RecipientId.from(serviceId)
val aci = ACI.parseOrThrow(callEvent.conversationId)
val recipientId = RecipientId.from(aci)
log(envelopeTimestamp, "Synchronize call event call: $callId")

View File

@@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.account.PreKeyUpload;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import java.io.IOException;

View File

@@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import java.io.IOException;

View File

@@ -14,7 +14,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.io.IOException;
import java.util.Objects;

View File

@@ -191,7 +191,7 @@ public final class MessageGroupContext {
List<RecipientId> members = new ArrayList<>(decryptedGroupV2Context.getGroupState().getMembersCount());
for (DecryptedMember member : decryptedGroupV2Context.getGroupState().getMembersList()) {
RecipientId recipient = RecipientId.from(ServiceId.fromByteString(member.getUuid()));
RecipientId recipient = RecipientId.from(ServiceId.parseOrThrow(member.getUuid()));
if (!Recipient.self().getId().equals(recipient)) {
members.add(recipient);
}

View File

@@ -13,8 +13,8 @@ import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
public class AccountManagerFactory {

View File

@@ -21,7 +21,7 @@ import org.signal.core.util.CursorUtil;
import org.thoughtcrime.securesms.util.LRUCache;
import org.signal.core.util.Stopwatch;
import org.thoughtcrime.securesms.util.concurrent.FilteredExecutor;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.util.ArrayList;
import java.util.Collection;
@@ -160,7 +160,7 @@ public final class LiveRecipientCache {
}
if (localAci != null) {
selfId = recipientTable.getByServiceId(localAci).orElse(null);
selfId = recipientTable.getByAci(localAci).orElse(null);
}
if (selfId == null && localE164 != null) {

View File

@@ -49,7 +49,8 @@ import org.thoughtcrime.securesms.util.AvatarUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.OptionalUtil;
@@ -86,7 +87,7 @@ public class Recipient {
private final RecipientId id;
private final boolean resolving;
private final ServiceId serviceId;
private final ACI aci;
private final PNI pni;
private final String username;
private final String e164;
@@ -219,8 +220,8 @@ public class Recipient {
* Create a recipient with a full (ACI, PNI, E164) tuple. It is assumed that the association between the PNI and serviceId is trusted.
* That means it must be from either storage service or a PNI verification message.
*/
public static @NonNull Recipient trustedPush(@NonNull ServiceId serviceId, @Nullable PNI pni, @Nullable String e164) {
if (ServiceId.UNKNOWN.equals(serviceId)) {
public static @NonNull Recipient trustedPush(@NonNull ACI aci, @Nullable PNI pni, @Nullable String e164) {
if (ACI.UNKNOWN.equals(aci) || PNI.UNKNOWN.equals(pni)) {
throw new AssertionError("Unknown serviceId!");
}
@@ -229,9 +230,9 @@ public class Recipient {
RecipientId recipientId;
if (FeatureFlags.phoneNumberPrivacy()) {
recipientId = db.getAndPossiblyMergePnpVerified(serviceId, pni, e164);
recipientId = db.getAndPossiblyMergePnpVerified(aci, pni, e164);
} else {
recipientId = db.getAndPossiblyMerge(serviceId, e164);
recipientId = db.getAndPossiblyMerge(aci, e164);
}
Recipient resolved = resolved(recipientId);
@@ -242,7 +243,7 @@ public class Recipient {
if (!resolved.isRegistered()) {
Log.w(TAG, "External push was locally marked unregistered. Marking as registered.");
db.markRegistered(recipientId, serviceId);
db.markRegistered(recipientId, aci);
}
return resolved;
@@ -259,7 +260,7 @@ public class Recipient {
*/
@WorkerThread
static @NonNull Recipient externalPush(@Nullable ServiceId serviceId, @Nullable String e164) {
if (ServiceId.UNKNOWN.equals(serviceId)) {
if (ACI.UNKNOWN.equals(serviceId) || PNI.UNKNOWN.equals(serviceId)) {
throw new AssertionError();
}
@@ -375,7 +376,7 @@ public class Recipient {
Recipient(@NonNull RecipientId id) {
this.id = id;
this.resolving = true;
this.serviceId = null;
this.aci = null;
this.pni = null;
this.username = null;
this.e164 = null;
@@ -433,7 +434,7 @@ public class Recipient {
public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) {
this.id = id;
this.resolving = !resolved;
this.serviceId = details.serviceId;
this.aci = details.aci;
this.pni = details.pni;
this.username = details.username;
this.e164 = details.e164;
@@ -661,7 +662,11 @@ public class Recipient {
}
public @NonNull Optional<ServiceId> getServiceId() {
return Optional.ofNullable(serviceId);
return OptionalUtil.or(Optional.ofNullable(aci), Optional.ofNullable(pni));
}
public @NonNull Optional<ACI> getAci() {
return Optional.ofNullable(aci);
}
public @NonNull Optional<PNI> getPni() {
@@ -750,6 +755,14 @@ public class Recipient {
return getServiceId().isPresent();
}
public boolean hasAci() {
return getAci().isPresent();
}
public boolean hasPni() {
return getPni().isPresent();
}
public boolean isServiceIdOnly() {
return hasServiceId() && !hasSmsAddress();
}
@@ -786,7 +799,22 @@ public class Recipient {
* The {@link ServiceId} of the user if available, otherwise throw.
*/
public @NonNull ServiceId requireServiceId() {
ServiceId resolved = resolving ? resolve().serviceId : serviceId;
Recipient resolved = resolving ? resolve() : this;
if (resolved.aci != null) {
return resolved.aci;
} else if (resolved.pni != null) {
return resolved.pni;
} else {
throw new MissingAddressError(id);
}
}
/**
* The {@link ACI} of the user if available, otherwise throw.
*/
public @NonNull ACI requireAci() {
ACI resolved = resolving ? resolve().aci : aci;
if (resolved == null) {
throw new MissingAddressError(id);
@@ -1326,7 +1354,7 @@ public class Recipient {
profileSharing == other.profileSharing &&
isHidden == other.isHidden &&
forceSmsSelection == other.forceSmsSelection &&
Objects.equals(serviceId, other.serviceId) &&
Objects.equals(aci, other.aci) &&
Objects.equals(username, other.username) &&
Objects.equals(e164, other.e164) &&
Objects.equals(email, other.email) &&

View File

@@ -26,8 +26,8 @@ import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import java.util.Collections;
import java.util.LinkedList;
@@ -36,7 +36,7 @@ import java.util.Optional;
public class RecipientDetails {
final ServiceId serviceId;
final ACI aci;
final PNI pni;
final String username;
final String e164;
@@ -108,7 +108,7 @@ public class RecipientDetails {
this.systemContactPhoto = Util.uri(record.getSystemContactPhotoUri());
this.customLabel = record.getSystemPhoneLabel();
this.contactUri = Util.uri(record.getSystemContactUri());
this.serviceId = record.getServiceId();
this.aci = record.getAci();
this.pni = record.getPni();
this.username = record.getUsername();
this.e164 = record.getE164();
@@ -165,7 +165,7 @@ public class RecipientDetails {
this.systemContactPhoto = null;
this.customLabel = null;
this.contactUri = null;
this.serviceId = null;
this.aci = null;
this.pni = null;
this.username = null;
this.e164 = null;
@@ -220,7 +220,7 @@ public class RecipientDetails {
public static @NonNull RecipientDetails forIndividual(@NonNull Context context, @NonNull RecipientRecord settings) {
boolean systemContact = !settings.getSystemProfileName().isEmpty();
boolean isSelf = (settings.getE164() != null && settings.getE164().equals(SignalStore.account().getE164())) ||
(settings.getServiceId() != null && settings.getServiceId().equals(SignalStore.account().getAci()));
(settings.getAci() != null && settings.getAci().equals(SignalStore.account().getAci()));
boolean isReleaseChannel = settings.getId().equals(SignalStore.releaseChannelValues().getReleaseChannelRecipientId());
RegisteredState registeredState = settings.getRegistered();

View File

@@ -38,8 +38,8 @@ import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.account.PreKeyCollection;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.Preconditions;
@@ -129,7 +129,7 @@ public final class RegistrationRepository {
Preconditions.checkNotNull(response.getPniPreKeyCollection(), "Missing PNI prekey collection!");
ACI aci = ACI.parseOrThrow(response.getVerifyAccountResponse().getUuid());
PNI pni = PNI.parseOrThrow(response.getVerifyAccountResponse().getPni());
PNI pni = PNI.parseUnPrefixedOrThrow(response.getVerifyAccountResponse().getPni());
boolean hasPin = response.getVerifyAccountResponse().isStorageCapable();
SignalStore.account().setAci(aci);

View File

@@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder
import org.webrtc.PeerConnection;
import org.webrtc.VideoTrack;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.ArrayList;
@@ -91,7 +92,7 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
seen.add(Recipient.self());
for (GroupCall.RemoteDeviceState device : remoteDeviceStates) {
Recipient recipient = Recipient.externalPush(ServiceId.from(device.getUserId()));
Recipient recipient = Recipient.externalPush(ACI.from(device.getUserId()));
CallParticipantId callParticipantId = new CallParticipantId(device.getDemuxId(), recipient.getId());
CallParticipant callParticipant = participants.get(callParticipantId);

View File

@@ -3,12 +3,12 @@ package org.thoughtcrime.securesms.service.webrtc
import org.signal.ringrtc.CallManager
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.recipients.RecipientId
import java.util.UUID
import org.whispersystems.signalservice.api.push.ServiceId.ACI
data class GroupCallRingCheckInfo(
val recipientId: RecipientId,
val groupId: GroupId.V2,
val ringId: Long,
val ringerUuid: UUID,
val ringerAci: ACI,
val ringUpdate: CallManager.RingUpdate
)

View File

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

View File

@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.List;
@@ -120,7 +121,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
}
List<Recipient> callParticipants = Stream.of(peekInfo.getJoinedMembers())
.map(uuid -> Recipient.externalPush(ServiceId.from(uuid)))
.map(uuid -> Recipient.externalPush(ACI.from(uuid)))
.toList();
WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder()

View File

@@ -17,8 +17,7 @@ import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import java.util.UUID;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
/**
* Action handler for when the system is at rest. Mainly responsible
@@ -97,7 +96,7 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
@NonNull RemotePeer remotePeerGroup,
@NonNull GroupId.V2 groupId,
long ringId,
@NonNull UUID sender,
@NonNull ACI sender,
@NonNull CallManager.RingUpdate ringUpdate)
{
Log.i(TAG, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + ringId + " update: " + ringUpdate);
@@ -154,11 +153,11 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
if (peekInfo.getDeviceCount() == 0) {
Log.i(TAG, "No one in the group call, mark as expired and do not ring");
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerUuid(), System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerAci(), System.currentTimeMillis(), CallManager.RingUpdate.EXPIRED_REQUEST);
return currentState;
} else if (peekInfo.getJoinedMembers().contains(Recipient.self().requireServiceId().uuid())) {
} else if (peekInfo.getJoinedMembers().contains(Recipient.self().requireServiceId().getRawUuid())) {
Log.i(TAG, "We are already in the call, mark accepted on another device and do not ring");
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerUuid(), System.currentTimeMillis(), CallManager.RingUpdate.ACCEPTED_ON_ANOTHER_DEVICE);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(info.getRingId(), info.getRecipientId(), info.getRingerAci(), System.currentTimeMillis(), CallManager.RingUpdate.ACCEPTED_ON_ANOTHER_DEVICE);
return currentState;
}
@@ -166,6 +165,6 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
.actionProcessor(new IncomingGroupCallActionProcessor(webRtcInteractor))
.build();
return currentState.getActionProcessor().handleGroupCallRingUpdate(currentState, new RemotePeer(info.getRecipientId()), info.getGroupId(), info.getRingId(), info.getRingerUuid(), info.getRingUpdate());
return currentState.getActionProcessor().handleGroupCallRingUpdate(currentState, new RemotePeer(info.getRecipientId()), info.getGroupId(), info.getRingId(), info.getRingerAci(), info.getRingUpdate());
}
}

View File

@@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Optional;
@@ -49,7 +50,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
@NonNull RemotePeer remotePeerGroup,
@NonNull GroupId.V2 groupId,
long ringId,
@NonNull UUID sender,
@NonNull ACI sender,
@NonNull CallManager.RingUpdate ringUpdate)
{
Log.i(TAG, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + Long.toHexString(ringId) + " update: " + ringUpdate);
@@ -108,7 +109,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
Log.i(TAG, "Requesting new ring: " + Long.toHexString(ringId));
Recipient ringerRecipient = Recipient.externalPush(ServiceId.from(sender));
Recipient ringerRecipient = Recipient.externalPush(sender);
SignalDatabase.calls().insertOrUpdateGroupCallFromRingState(
ringId,
remotePeerGroup.getId(),

View File

@@ -80,7 +80,7 @@ import org.whispersystems.signalservice.api.messages.calls.OpaqueMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage;
@@ -191,7 +191,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
serviceExecutor.execute(() -> {
if (needsToSetSelfUuid) {
try {
callManager.setSelfUuid(SignalStore.account().requireAci().uuid());
callManager.setSelfUuid(SignalStore.account().requireAci().getRawUuid());
needsToSetSelfUuid = false;
} catch (CallException e) {
Log.w(TAG, "Unable to set self UUID on CallManager", e);
@@ -724,14 +724,14 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
}
@Override
public void onSendCallMessage(@NonNull UUID uuid, @NonNull byte[] bytes, @NonNull CallManager.CallMessageUrgency urgency) {
public void onSendCallMessage(@NonNull UUID aciUuid, @NonNull byte[] bytes, @NonNull CallManager.CallMessageUrgency urgency) {
Log.i(TAG, "onSendCallMessage():");
OpaqueMessage opaqueMessage = new OpaqueMessage(bytes, getUrgencyFromCallUrgency(urgency));
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forOpaque(opaqueMessage, true, null);
networkExecutor.execute(() -> {
Recipient recipient = Recipient.resolved(RecipientId.from(ServiceId.from(uuid)));
Recipient recipient = Recipient.resolved(RecipientId.from(ACI.from(aciUuid)));
if (recipient.isBlocked()) {
return;
}
@@ -826,16 +826,17 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
@Override
public void onGroupCallRingUpdate(@NonNull byte[] groupIdBytes, long ringId, @NonNull UUID sender, @NonNull CallManager.RingUpdate ringUpdate) {
try {
ACI senderAci = ACI.from(sender);
GroupId.V2 groupId = GroupId.v2(new GroupIdentifier(groupIdBytes));
GroupRecord group = SignalDatabase.groups().getGroup(groupId).orElse(null);
Recipient senderRecipient = Recipient.externalPush(ServiceId.from(sender));
Recipient senderRecipient = Recipient.externalPush(senderAci);
if (group != null &&
group.isActive() &&
!Recipient.resolved(group.getRecipientId()).isBlocked() &&
(!group.isAnnouncementGroup() || group.isAdmin(senderRecipient)))
{
process((s, p) -> p.handleGroupCallRingUpdate(s, new RemotePeer(group.getRecipientId()), groupId, ringId, sender, ringUpdate));
process((s, p) -> p.handleGroupCallRingUpdate(s, new RemotePeer(group.getRecipientId()), groupId, ringId, senderAci, ringUpdate));
} else {
Log.w(TAG, "Unable to ring unknown/inactive/blocked group.");
}

View File

@@ -54,6 +54,7 @@ import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.util.Collection;
import java.util.List;
@@ -789,7 +790,7 @@ public abstract class WebRtcActionProcessor {
@NonNull RemotePeer remotePeerGroup,
@NonNull GroupId.V2 groupId,
long ringId,
@NonNull UUID sender,
@NonNull ACI sender,
@NonNull RingUpdate ringUpdate)
{
Log.i(tag, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + ringId + " update: " + ringUpdate);

View File

@@ -45,7 +45,7 @@ class SignalCallLinkManager(
linkRootKey: ByteArray,
roomId: ByteArray
): CreateCallLinkCredentialPresentation {
val userUuid = Recipient.self().requireServiceId().uuid()
val userUuid = Recipient.self().requireAci().rawUuid
val requestContext = CreateCallLinkCredentialRequestContext.forRoom(roomId)
val request = requestContext.request

View File

@@ -12,8 +12,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.util.OptionalUtil;
@@ -26,7 +26,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
@@ -81,9 +80,9 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
continue;
}
if (remoteRecord.getUnregisteredTimestamp() > 0 && remoteRecord.getServiceId() != null && !remoteRecord.getPni().isPresent() && !remoteRecord.getNumber().isPresent()) {
if (remoteRecord.getUnregisteredTimestamp() > 0 && remoteRecord.getAci() != null && !remoteRecord.getPni().isPresent() && !remoteRecord.getNumber().isPresent()) {
unregisteredAciOnly.add(remoteRecord);
} else if (remoteRecord.getServiceId() != null && remoteRecord.getServiceId().equals(remoteRecord.getPni().orElse(null))) {
} else if (remoteRecord.getAci() != null && remoteRecord.getAci().equals(remoteRecord.getPni().orElse(null))) {
pniE164Only.add(remoteRecord);
}
}
@@ -128,22 +127,19 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
*/
@Override
boolean isInvalid(@NonNull SignalContactRecord remote) {
if (remote.getServiceId() == null) {
if (remote.getAci() == null) {
Log.w(TAG, "No address on the ContentRecord -- marking as invalid.");
return true;
} else if (remote.getServiceId().isUnknown()) {
} else if (remote.getAci().isUnknown()) {
Log.w(TAG, "Found a ContactRecord without a UUID -- marking as invalid.");
return true;
} else if (remote.getServiceId().equals(selfAci) ||
remote.getServiceId().equals(selfPni) ||
} else if (remote.getAci().equals(selfAci) ||
remote.getAci().equals(selfPni) ||
(selfPni != null && selfPni.equals(remote.getPni().orElse(null))) ||
(selfE164 != null && remote.getNumber().isPresent() && remote.getNumber().get().equals(selfE164)))
{
Log.w(TAG, "Found a ContactRecord for ourselves -- marking as invalid.");
return true;
} else if (!FeatureFlags.phoneNumberPrivacy() && remote.getServiceId().equals(remote.getPni().orElse(null))) {
Log.w(TAG, "Found a PNI-only ContactRecord when PNP is disabled -- marking as invalid.");
return true;
} else if (remote.getNumber().isPresent() && !isValidE164(remote.getNumber().get())) {
Log.w(TAG, "Found a record with an invalid E164. Marking as invalid.");
return true;
@@ -158,17 +154,13 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
remote = remote.withoutPni();
}
Optional<RecipientId> found = recipientTable.getByServiceId(remote.getServiceId());
Optional<RecipientId> found = recipientTable.getByAci(remote.getAci());
if (!found.isPresent() && remote.getNumber().isPresent()) {
if (found.isEmpty() && remote.getNumber().isPresent()) {
found = recipientTable.getByE164(remote.getNumber().get());
}
if (!found.isPresent() && remote.getPni().isPresent()) {
found = recipientTable.getByServiceId(remote.getPni().get());
}
if (!found.isPresent() && remote.getPni().isPresent()) {
if (found.isEmpty() && remote.getPni().isPresent()) {
found = recipientTable.getByPni(remote.getPni().get());
}
@@ -219,8 +211,8 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
}
if (identityKey != null && remote.getIdentityKey().isPresent() && !Arrays.equals(identityKey, remote.getIdentityKey().get())) {
Log.w(TAG, "The local and remote identity keys do not match for " + local.getServiceId() + ". Enqueueing a profile fetch.");
RetrieveProfileJob.enqueue(Recipient.trustedPush(local.getServiceId(), local.getPni().orElse(null), local.getNumber().orElse(null)).getId());
Log.w(TAG, "The local and remote identity keys do not match for " + local.getAci() + ". Enqueueing a profile fetch.");
RetrieveProfileJob.enqueue(Recipient.trustedPush(local.getAci(), local.getPni().orElse(null), local.getNumber().orElse(null)).getId());
}
PNI pni;
@@ -259,7 +251,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
}
byte[] unknownFields = remote.serializeUnknownFields();
ServiceId serviceId = local.getServiceId() == ServiceId.UNKNOWN ? remote.getServiceId() : local.getServiceId();
ACI aci = local.getAci() == ACI.UNKNOWN ? remote.getAci() : local.getAci();
byte[] profileKey = OptionalUtil.or(remote.getProfileKey(), local.getProfileKey()).orElse(null);
String username = OptionalUtil.or(remote.getUsername(), local.getUsername()).orElse("");
boolean blocked = remote.isBlocked();
@@ -273,15 +265,15 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
String systemGivenName = SignalStore.account().isPrimaryDevice() ? local.getSystemGivenName().orElse("") : remote.getSystemGivenName().orElse("");
String systemFamilyName = SignalStore.account().isPrimaryDevice() ? local.getSystemFamilyName().orElse("") : remote.getSystemFamilyName().orElse("");
String systemNickname = remote.getSystemNickname().orElse("");
boolean matchesRemote = doParamsMatch(remote, unknownFields, serviceId, pni, e164, profileGivenName, profileFamilyName, systemGivenName, systemFamilyName, systemNickname, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
boolean matchesLocal = doParamsMatch(local, unknownFields, serviceId, pni, e164, profileGivenName, profileFamilyName, systemGivenName, systemFamilyName, systemNickname, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
boolean matchesRemote = doParamsMatch(remote, unknownFields, aci, pni, e164, profileGivenName, profileFamilyName, systemGivenName, systemFamilyName, systemNickname, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
boolean matchesLocal = doParamsMatch(local, unknownFields, aci, pni, e164, profileGivenName, profileFamilyName, systemGivenName, systemFamilyName, systemNickname, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
if (matchesRemote) {
return remote;
} else if (matchesLocal) {
return local;
} else {
return new SignalContactRecord.Builder(keyGenerator.generate(), serviceId, unknownFields)
return new SignalContactRecord.Builder(keyGenerator.generate(), aci, unknownFields)
.setE164(e164)
.setPni(pni)
.setProfileGivenName(profileGivenName)
@@ -317,7 +309,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
@Override
public int compare(@NonNull SignalContactRecord lhs, @NonNull SignalContactRecord rhs) {
if (Objects.equals(lhs.getServiceId(), rhs.getServiceId()) ||
if (Objects.equals(lhs.getAci(), rhs.getAci()) ||
(lhs.getNumber().isPresent() && Objects.equals(lhs.getNumber(), rhs.getNumber())) ||
(lhs.getPni().isPresent() && Objects.equals(lhs.getPni(), rhs.getPni())))
{
@@ -355,7 +347,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
boolean hidden)
{
return Arrays.equals(contact.serializeUnknownFields(), unknownFields) &&
Objects.equals(contact.getServiceId(), serviceId) &&
Objects.equals(contact.getAci(), serviceId) &&
Objects.equals(contact.getPni().orElse(null), pni) &&
Objects.equals(contact.getNumber().orElse(null), e164) &&
Objects.equals(contact.getProfileGivenName().orElse(""), profileGivenName) &&

View File

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

View File

@@ -164,7 +164,7 @@ public final class StorageSyncValidations {
if (insert.getContact().isPresent()) {
SignalContactRecord contact = insert.getContact().get();
if (self.requireServiceId().equals(contact.getServiceId()) ||
if (self.requireAci().equals(contact.getAci()) ||
self.requirePni().equals(contact.getPni().orElse(null)) ||
self.requireE164().equals(contact.getNumber().orElse("")))
{

View File

@@ -8,15 +8,11 @@ import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.mms.PushMediaConstraints;
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* Provide access to locale specific values within feature flags following the locale CSV-Colon format.
@@ -85,7 +81,7 @@ public final class LocaleFeatureFlags {
}
long countEnabled = getCountryValue(countryCodeValues, self.getE164().orElse(""), 0);
long currentUserBucket = BucketingUtil.bucket(flag, self.requireServiceId().uuid(), 1_000_000);
long currentUserBucket = BucketingUtil.bucket(flag, self.requireAci().getRawUuid(), 1_000_000);
return countEnabled > currentUserBucket;
}

View File

@@ -13,7 +13,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.util.Base64UrlSafe;

View File

@@ -63,9 +63,9 @@ class VerifySafetyNumberViewModel(
e164Fingerprint = SafetyNumberFingerprint(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity, generator.createFor(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity))
}
if (resolved.serviceId.isPresent) {
if (resolved.aci.isPresent) {
val localIdentifier = SignalStore.account().requireAci().toByteArray()
val remoteIdentifier = resolved.requireServiceId().toByteArray()
val remoteIdentifier = resolved.requireAci().toByteArray()
val version = 2
aciFingerprint = SafetyNumberFingerprint(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity, generator.createFor(version, localIdentifier, localIdentity, remoteIdentifier, remoteIdentity))
}
@@ -97,13 +97,13 @@ class VerifySafetyNumberViewModel(
val context: Context = ApplicationDependencies.getApplication()
SignalExecutors.BOUNDED.execute {
ReentrantSessionLock.INSTANCE.acquire().use { unused ->
ReentrantSessionLock.INSTANCE.acquire().use { _ ->
if (verified) {
Log.i(TAG, "Saving identity: $recipientId")
ApplicationDependencies.getProtocolStore().aci().identities()
.saveIdentityWithoutSideEffects(
recipientId,
recipient.resolve().requireServiceId(),
recipient.resolve().requireAci(),
remoteIdentity,
IdentityTable.VerifiedStatus.VERIFIED,
false,