mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-24 17:18:54 +01:00
Adopt libsignal 0.30.0 and ServiceIds for group members.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
This commit is contained in:
committed by
Greyson Parrelli
parent
b11d653fc0
commit
a2c3b5d64e
+2
-2
@@ -153,8 +153,8 @@ class ConversationSettingsRepository(
|
||||
if (groupRecord.isV2Group) {
|
||||
val decryptedGroup: DecryptedGroup = groupRecord.requireV2GroupProperties().decryptedGroup
|
||||
val pendingMembers: List<RecipientId> = decryptedGroup.pendingMembersList
|
||||
.map(DecryptedPendingMember::getUuid)
|
||||
.map(GroupProtoUtil::uuidByteStringToRecipientId)
|
||||
.map(DecryptedPendingMember::getServiceIdBinary)
|
||||
.map(GroupProtoUtil::serviceIdBinaryToRecipientId)
|
||||
|
||||
val members = mutableListOf<RecipientId>()
|
||||
|
||||
|
||||
+8
-7
@@ -50,6 +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;
|
||||
@@ -291,11 +292,11 @@ public final class ConversationUpdateItem extends FrameLayout
|
||||
|
||||
private final Observer<Object> updater;
|
||||
|
||||
private LiveGroup liveGroup;
|
||||
private LiveData<Boolean> liveIsSelfAdmin;
|
||||
private LiveData<Set<UUID>> liveBannedMembers;
|
||||
private LiveData<Set<UUID>> liveFullMembers;
|
||||
private Recipient conversationRecipient;
|
||||
private LiveGroup liveGroup;
|
||||
private LiveData<Boolean> liveIsSelfAdmin;
|
||||
private LiveData<Set<ServiceId>> liveBannedMembers;
|
||||
private LiveData<Set<UUID>> liveFullMembers;
|
||||
private Recipient conversationRecipient;
|
||||
|
||||
GroupDataManager() {
|
||||
this.updater = unused -> update();
|
||||
@@ -341,9 +342,9 @@ public final class ConversationUpdateItem extends FrameLayout
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<UUID> bannedMembers = liveBannedMembers.getValue();
|
||||
Set<ServiceId> bannedMembers = liveBannedMembers.getValue();
|
||||
if (bannedMembers != null) {
|
||||
return recipient.getServiceId().isPresent() && bannedMembers.contains(recipient.requireServiceId().getRawUuid());
|
||||
return recipient.getServiceId().isPresent() && bannedMembers.contains(recipient.requireServiceId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ import org.whispersystems.signalservice.api.util.UuidUtil
|
||||
import java.io.Closeable
|
||||
import java.security.SecureRandom
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.stream.Collectors
|
||||
import javax.annotation.CheckReturnValue
|
||||
|
||||
@@ -861,8 +860,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
writableDatabase.withinTransaction { db ->
|
||||
val record = getGroup(groupIdV1).get()
|
||||
|
||||
val newMembers: MutableList<RecipientId> = DecryptedGroupUtil.membersToUuidList(decryptedGroup.membersList).toRecipientIds()
|
||||
val pendingMembers: List<RecipientId> = DecryptedGroupUtil.pendingToUuidList(decryptedGroup.pendingMembersList).toRecipientIds()
|
||||
val newMembers: MutableList<RecipientId> = DecryptedGroupUtil.membersToServiceIdList(decryptedGroup.membersList).toRecipientIds()
|
||||
val pendingMembers: List<RecipientId> = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembersList).toRecipientIds()
|
||||
newMembers.addAll(pendingMembers)
|
||||
|
||||
val droppedMembers: List<RecipientId> = SetUtil.difference(record.members, newMembers).toList()
|
||||
@@ -915,11 +914,11 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
|
||||
val change = GroupChangeReconstruct.reconstructGroupChange(existingGroup.get().requireV2GroupProperties().decryptedGroup, decryptedGroup)
|
||||
|
||||
val addedMembers: Set<RecipientId> = DecryptedGroupUtil.membersToUuidList(change.newMembersList).toRecipientIds().toSet()
|
||||
val removedMembers: Set<RecipientId> = DecryptedGroupUtil.removedMembersUuidList(change).toRecipientIds().toSet()
|
||||
val addedInvites: Set<RecipientId> = DecryptedGroupUtil.pendingToUuidList(change.newPendingMembersList).toRecipientIds().toSet()
|
||||
val removedInvites: Set<RecipientId> = DecryptedGroupUtil.removedPendingMembersUuidList(change).toRecipientIds().toSet()
|
||||
val acceptedInvites: Set<RecipientId> = DecryptedGroupUtil.membersToUuidList(change.promotePendingMembersList).toRecipientIds().toSet()
|
||||
val addedMembers: Set<RecipientId> = DecryptedGroupUtil.membersToServiceIdList(change.newMembersList).toRecipientIds().toSet()
|
||||
val removedMembers: Set<RecipientId> = DecryptedGroupUtil.removedMembersServiceIdList(change).toRecipientIds().toSet()
|
||||
val addedInvites: Set<RecipientId> = DecryptedGroupUtil.pendingToServiceIdList(change.newPendingMembersList).toRecipientIds().toSet()
|
||||
val removedInvites: Set<RecipientId> = DecryptedGroupUtil.removedPendingMembersServiceIdList(change).toRecipientIds().toSet()
|
||||
val acceptedInvites: Set<RecipientId> = DecryptedGroupUtil.membersToServiceIdList(change.promotePendingMembersList).toRecipientIds().toSet()
|
||||
|
||||
unmigratedV1Members -= addedMembers
|
||||
unmigratedV1Members -= removedMembers
|
||||
@@ -934,7 +933,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
|
||||
if (existingGroup.isPresent && existingGroup.get().isV2Group) {
|
||||
val change = GroupChangeReconstruct.reconstructGroupChange(existingGroup.get().requireV2GroupProperties().decryptedGroup, decryptedGroup)
|
||||
val removed: List<UUID> = DecryptedGroupUtil.removedMembersUuidList(change)
|
||||
val removed: List<ServiceId> = DecryptedGroupUtil.removedMembersServiceIdList(change)
|
||||
|
||||
if (removed.isNotEmpty()) {
|
||||
val distributionId = existingGroup.get().distributionId!!
|
||||
@@ -1208,8 +1207,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
DecryptedGroup.parseFrom(decryptedGroupBytes)
|
||||
}
|
||||
|
||||
val bannedMembers: Set<UUID> by lazy {
|
||||
DecryptedGroupUtil.bannedMembersToUuidSet(decryptedGroup.bannedMembersList)
|
||||
val bannedMembers: Set<ServiceId> by lazy {
|
||||
DecryptedGroupUtil.bannedMembersToServiceIdSet(decryptedGroup.bannedMembersList)
|
||||
}
|
||||
|
||||
fun isAdmin(recipient: Recipient): Boolean {
|
||||
@@ -1243,7 +1242,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
}
|
||||
|
||||
if (memberLevel.isAbsent()) {
|
||||
memberLevel = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, serviceId.get().rawUuid)
|
||||
memberLevel = DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembersList, serviceId.get())
|
||||
.map { MemberLevel.PENDING_MEMBER }
|
||||
}
|
||||
|
||||
@@ -1265,7 +1264,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
|
||||
fun getMemberRecipientIds(memberSet: MemberSet): List<RecipientId> {
|
||||
val includeSelf = memberSet.includeSelf
|
||||
val selfAciUuid = SignalStore.account().requireAci().rawUuid
|
||||
val selfAci = SignalStore.account().requireAci()
|
||||
val selfAciUuid = selfAci.rawUuid
|
||||
val recipients: MutableList<RecipientId> = ArrayList(decryptedGroup.membersCount + decryptedGroup.pendingMembersCount)
|
||||
|
||||
var unknownMembers = 0
|
||||
@@ -1280,11 +1280,11 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
}
|
||||
|
||||
if (memberSet.includePending) {
|
||||
for (uuid in DecryptedGroupUtil.pendingToUuidList(decryptedGroup.pendingMembersList)) {
|
||||
if (UuidUtil.UNKNOWN_UUID == uuid) {
|
||||
for (serviceId in DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembersList)) {
|
||||
if (serviceId.isUnknown) {
|
||||
unknownPending++
|
||||
} else if (includeSelf || selfAciUuid != uuid) {
|
||||
recipients += RecipientId.from(ACI.from(uuid))
|
||||
} else if (includeSelf || selfAci != serviceId) {
|
||||
recipients += RecipientId.from(serviceId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1378,11 +1378,11 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
val aci = SignalStore.account().requireAci()
|
||||
|
||||
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.membersList, aci.rawUuid).isPresent ||
|
||||
DecryptedGroupUtil.findPendingByUuid(decryptedGroup.pendingMembersList, aci.rawUuid).isPresent
|
||||
DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembersList, aci).isPresent
|
||||
}
|
||||
|
||||
private fun List<UUID>.toRecipientIds(): MutableList<RecipientId> {
|
||||
return uuidsToRecipientIds(this)
|
||||
private fun List<ServiceId>.toRecipientIds(): MutableList<RecipientId> {
|
||||
return serviceIdsToRecipientIds(this.asSequence())
|
||||
}
|
||||
|
||||
private fun Collection<RecipientId>.serialize(): String {
|
||||
@@ -1398,15 +1398,14 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
}
|
||||
}
|
||||
|
||||
private fun uuidsToRecipientIds(uuids: List<UUID>): MutableList<RecipientId> {
|
||||
return uuids
|
||||
.asSequence()
|
||||
.map { uuid ->
|
||||
if (uuid == UuidUtil.UNKNOWN_UUID) {
|
||||
private fun serviceIdsToRecipientIds(serviceIds: Sequence<ServiceId>): MutableList<RecipientId> {
|
||||
return serviceIds
|
||||
.map { serviceId ->
|
||||
if (serviceId.isUnknown) {
|
||||
Log.w(TAG, "Saw an unknown UUID when mapping to RecipientIds!")
|
||||
null
|
||||
} else {
|
||||
val id = RecipientId.from(ACI.from(uuid))
|
||||
val id = RecipientId.from(serviceId)
|
||||
val remapped = RemappedRecords.getInstance().getRecipient(id)
|
||||
if (remapped.isPresent) {
|
||||
Log.w(TAG, "Saw that $id remapped to $remapped. Using the mapping.")
|
||||
@@ -1422,8 +1421,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
}
|
||||
|
||||
private fun getV2GroupMembers(decryptedGroup: DecryptedGroup, shouldRetry: Boolean): List<RecipientId> {
|
||||
val uuids: List<UUID> = DecryptedGroupUtil.membersToUuidList(decryptedGroup.membersList)
|
||||
val ids: List<RecipientId> = uuidsToRecipientIds(uuids)
|
||||
val ids: List<RecipientId> = DecryptedGroupUtil.membersToServiceIdList(decryptedGroup.membersList).toRecipientIds()
|
||||
|
||||
return if (RemappedRecords.getInstance().areAnyRemapped(ids)) {
|
||||
if (shouldRetry) {
|
||||
|
||||
@@ -142,7 +142,6 @@ 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
|
||||
@@ -3089,10 +3088,9 @@ 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(ACI.from(uuid)) }
|
||||
.map { serviceId -> RecipientId.from(serviceId) }
|
||||
.toList()
|
||||
|
||||
members -= Recipient.self().id
|
||||
|
||||
@@ -176,7 +176,7 @@ class GroupRecord(
|
||||
if (isV2Group) {
|
||||
val serviceId = recipient.serviceId
|
||||
if (serviceId.isPresent) {
|
||||
return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get().rawUuid)
|
||||
return DecryptedGroupUtil.findPendingByServiceId(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get())
|
||||
.isPresent
|
||||
}
|
||||
}
|
||||
|
||||
+28
-27
@@ -33,6 +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 +73,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().getRawUuid());
|
||||
Optional<DecryptedPendingMember> selfPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfIds.getAci());
|
||||
if (!selfPending.isPresent() && selfIds.getPni() != null) {
|
||||
selfPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfIds.getPni().getRawUuid());
|
||||
selfPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfIds.getPni());
|
||||
}
|
||||
|
||||
if (selfPending.isPresent()) {
|
||||
@@ -310,13 +311,13 @@ final class GroupsV2UpdateMessageProducer {
|
||||
int notYouInviteCount = 0;
|
||||
|
||||
for (DecryptedPendingMember invitee : change.getNewPendingMembersList()) {
|
||||
boolean newMemberIsYou = selfIds.matches(invitee.getUuid());
|
||||
boolean newMemberIsYou = selfIds.matches(invitee.getServiceIdBinary());
|
||||
|
||||
if (newMemberIsYou) {
|
||||
updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, change.getEditor(), R.drawable.ic_update_group_add_16));
|
||||
} else {
|
||||
if (editorIsYou) {
|
||||
updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, invitee.getUuid(), R.drawable.ic_update_group_add_16));
|
||||
updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, invitee.getServiceIdBinary(), R.drawable.ic_update_group_add_16));
|
||||
} else {
|
||||
notYouInviteCount++;
|
||||
}
|
||||
@@ -332,7 +333,7 @@ final class GroupsV2UpdateMessageProducer {
|
||||
int notYouInviteCount = 0;
|
||||
|
||||
for (DecryptedPendingMember invitee : change.getNewPendingMembersList()) {
|
||||
boolean newMemberIsYou = selfIds.matches(invitee.getUuid());
|
||||
boolean newMemberIsYou = selfIds.matches(invitee.getServiceIdBinary());
|
||||
|
||||
if (newMemberIsYou) {
|
||||
UUID uuid = UuidUtil.fromByteStringOrUnknown(invitee.getAddedByUuid());
|
||||
@@ -357,14 +358,14 @@ final class GroupsV2UpdateMessageProducer {
|
||||
int notDeclineCount = 0;
|
||||
|
||||
for (DecryptedPendingMemberRemoval invitee : change.getDeletePendingMembersList()) {
|
||||
boolean decline = invitee.getUuid().equals(change.getEditor());
|
||||
boolean decline = invitee.getServiceIdBinary().equals(change.getEditor());
|
||||
if (decline) {
|
||||
if (editorIsYou) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_declined_the_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
|
||||
} else {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_someone_declined_an_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
|
||||
}
|
||||
} else if (selfIds.matches(invitee.getUuid())) {
|
||||
} else if (selfIds.matches(invitee.getServiceIdBinary())) {
|
||||
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, change.getEditor(), R.drawable.ic_update_group_decline_16));
|
||||
} else {
|
||||
notDeclineCount++;
|
||||
@@ -384,7 +385,7 @@ final class GroupsV2UpdateMessageProducer {
|
||||
int notDeclineCount = 0;
|
||||
|
||||
for (DecryptedPendingMemberRemoval invitee : change.getDeletePendingMembersList()) {
|
||||
boolean inviteeWasYou = selfIds.matches(invitee.getUuid());
|
||||
boolean inviteeWasYou = selfIds.matches(invitee.getServiceIdBinary());
|
||||
|
||||
if (inviteeWasYou) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
|
||||
@@ -817,14 +818,14 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
|
||||
private UpdateDescription updateDescription(@StringRes int stringRes,
|
||||
@NonNull ByteString uuid1Bytes,
|
||||
@NonNull ByteString serviceId1Bytes,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ACI aci = ACI.parseOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(aci);
|
||||
ACI serviceId = ACI.parseOrUnknown(serviceId1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(serviceId);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Collections.singletonList(aci),
|
||||
Collections.singletonList(serviceId),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Collections.singletonList(recipientId);
|
||||
String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, null));
|
||||
@@ -835,18 +836,18 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
|
||||
private UpdateDescription updateDescription(@StringRes int stringRes,
|
||||
@NonNull ByteString uuid1Bytes,
|
||||
@NonNull ByteString uuid2Bytes,
|
||||
@NonNull ByteString serviceId1Bytes,
|
||||
@NonNull ByteString serviceId2Bytes,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ACI aci1 = ACI.parseOrUnknown(uuid1Bytes);
|
||||
ACI aci2 = ACI.parseOrUnknown(uuid2Bytes);
|
||||
ACI serviceId1 = ACI.parseOrUnknown(serviceId1Bytes);
|
||||
ACI serviceId2 = ACI.parseOrUnknown(serviceId2Bytes);
|
||||
|
||||
RecipientId recipientId1 = RecipientId.from(aci1);
|
||||
RecipientId recipientId2 = RecipientId.from(aci2);
|
||||
RecipientId recipientId1 = RecipientId.from(serviceId1);
|
||||
RecipientId recipientId2 = RecipientId.from(serviceId2);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Arrays.asList(aci1, aci2),
|
||||
Arrays.asList(serviceId1, serviceId2),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Arrays.asList(recipientId1, recipientId2);
|
||||
String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, null));
|
||||
@@ -858,15 +859,15 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
|
||||
private UpdateDescription updateDescription(@StringRes int stringRes,
|
||||
@NonNull ByteString uuid1Bytes,
|
||||
@NonNull ByteString serviceId1Bytes,
|
||||
@NonNull Object formatArg,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ACI aci = ACI.parseOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(aci);
|
||||
ACI serviceId = ACI.parseOrUnknown(serviceId1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(serviceId);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Collections.singletonList(aci),
|
||||
Collections.singletonList(serviceId),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Collections.singletonList(recipientId);
|
||||
String templateString = context.getString(stringRes, makePlaceholders(recipientIdList, Collections.singletonList(formatArg)));
|
||||
@@ -879,15 +880,15 @@ final class GroupsV2UpdateMessageProducer {
|
||||
|
||||
private UpdateDescription updateDescription(@PluralsRes int stringRes,
|
||||
int quantity,
|
||||
@NonNull ByteString uuid1Bytes,
|
||||
@NonNull ByteString serviceId1Bytes,
|
||||
@NonNull Object formatArg,
|
||||
@DrawableRes int iconResource)
|
||||
{
|
||||
ACI aci = ACI.parseOrUnknown(uuid1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(aci);
|
||||
ACI serviceId = ACI.parseOrUnknown(serviceId1Bytes);
|
||||
RecipientId recipientId = RecipientId.from(serviceId);
|
||||
|
||||
return UpdateDescription.mentioning(
|
||||
Collections.singletonList(aci),
|
||||
Collections.singletonList(serviceId),
|
||||
() -> {
|
||||
List<RecipientId> recipientIdList = Collections.singletonList(recipientId);
|
||||
String templateString = context.getResources().getQuantityString(stringRes, quantity, makePlaceholders(recipientIdList, Collections.singletonList(formatArg)));
|
||||
|
||||
@@ -346,7 +346,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
}
|
||||
|
||||
DecryptedGroup groupState = decryptedGroupV2Context.getGroupState();
|
||||
boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), SignalStore.account().requireAci().getRawUuid()).isPresent();
|
||||
boolean invited = DecryptedGroupUtil.findPendingByServiceId(groupState.getPendingMembersList(), SignalStore.account().requireAci()).isPresent();
|
||||
|
||||
if (decryptedGroupV2Context.hasChange()) {
|
||||
UUID changeEditor = UuidUtil.fromByteStringOrNull(decryptedGroupV2Context.getChange().getEditor());
|
||||
|
||||
@@ -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().getRawUuid()));
|
||||
editor.unban(Collections.singleton(Recipient.resolved(recipientId).requireServiceId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ final class GroupManagerV2 {
|
||||
|
||||
Map<UUID, UuidCiphertext> uuidCipherTexts = new HashMap<>();
|
||||
for (Recipient recipient : recipients) {
|
||||
uuidCipherTexts.put(recipient.requireServiceId().getRawUuid(), clientZkGroupCipher.encryptUuid(recipient.requireServiceId().getRawUuid()));
|
||||
uuidCipherTexts.put(recipient.requireServiceId().getRawUuid(), clientZkGroupCipher.encrypt(recipient.requireServiceId().getLibSignalServiceId()));
|
||||
}
|
||||
|
||||
return uuidCipherTexts;
|
||||
@@ -343,7 +343,7 @@ final class GroupManagerV2 {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@NonNull GroupManager.GroupActionResult addMembers(@NonNull Collection<RecipientId> newMembers, @NonNull Set<UUID> bannedMembers)
|
||||
@NonNull GroupManager.GroupActionResult addMembers(@NonNull Collection<RecipientId> newMembers, @NonNull Set<ServiceId> bannedMembers)
|
||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException, MembershipNotSuitableForV2Exception
|
||||
{
|
||||
if (!GroupsV2CapabilityChecker.allHaveServiceId(newMembers)) {
|
||||
@@ -356,7 +356,7 @@ final class GroupManagerV2 {
|
||||
groupCandidates = GroupCandidate.withoutExpiringProfileKeyCredentials(groupCandidates);
|
||||
}
|
||||
|
||||
return commitChangeWithConflictResolution(selfAci, groupOperations.createModifyGroupMembershipChange(groupCandidates, bannedMembers, selfAci.getRawUuid()));
|
||||
return commitChangeWithConflictResolution(selfAci, groupOperations.createModifyGroupMembershipChange(groupCandidates, bannedMembers, selfAci));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -454,7 +454,7 @@ final class GroupManagerV2 {
|
||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||
{
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
return commitChangeWithConflictResolution(selfAci, groupOperations.createChangeMemberRole(recipient.requireServiceId().getRawUuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
|
||||
return commitChangeWithConflictResolution(selfAci, groupOperations.createChangeMemberRole(recipient.requireAci(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -464,8 +464,8 @@ final class GroupManagerV2 {
|
||||
GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
||||
DecryptedGroup decryptedGroup = groupRecord.requireV2GroupProperties().getDecryptedGroup();
|
||||
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> aciPendingMember = DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.getPendingMembersList(), selfAci);
|
||||
Optional<DecryptedPendingMember> pniPendingMember = DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.getPendingMembersList(), selfPni);
|
||||
Optional<DecryptedPendingMember> selfPendingMember = Optional.empty();
|
||||
ServiceId serviceId = selfAci;
|
||||
|
||||
@@ -555,8 +555,8 @@ final class GroupManagerV2 {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<DecryptedPendingMember> aciInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfAci.getRawUuid());
|
||||
Optional<DecryptedPendingMember> pniInPending = DecryptedGroupUtil.findPendingByUuid(group.getPendingMembersList(), selfPni.getRawUuid());
|
||||
Optional<DecryptedPendingMember> aciInPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfAci);
|
||||
Optional<DecryptedPendingMember> pniInPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfPni);
|
||||
|
||||
GroupCandidate groupCandidate = groupCandidateHelper.recipientIdToCandidate(Recipient.self().getId());
|
||||
|
||||
@@ -584,10 +584,10 @@ final class GroupManagerV2 {
|
||||
return commitChangeWithConflictResolution(selfAci, groupOperations.createBanUuidsChange(Collections.singleton(uuid), rejectJoinRequest, v2GroupProperties.getDecryptedGroup().getBannedMembersList()));
|
||||
}
|
||||
|
||||
public GroupManager.GroupActionResult unban(Set<UUID> uuids)
|
||||
public GroupManager.GroupActionResult unban(Set<ServiceId> serviceIds)
|
||||
throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException
|
||||
{
|
||||
return commitChangeWithConflictResolution(selfAci, groupOperations.createUnbanUuidsChange(uuids));
|
||||
return commitChangeWithConflictResolution(selfAci, groupOperations.createUnbanServiceIdsChange(serviceIds));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -704,7 +704,7 @@ final class GroupManagerV2 {
|
||||
GroupChange.Actions changeActions = change.build();
|
||||
|
||||
return GroupChangeUtil.resolveConflict(groupUpdateResult.getLatestServer(),
|
||||
groupOperations.decryptChange(changeActions, authServiceId.getRawUuid()),
|
||||
groupOperations.decryptChange(changeActions, authServiceId),
|
||||
changeActions);
|
||||
} catch (VerificationFailedException | InvalidGroupStateException ex) {
|
||||
throw new GroupChangeFailedException(ex);
|
||||
@@ -1331,9 +1331,8 @@ 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(ACI.from(uuid)))
|
||||
return Stream.of(DecryptedGroupUtil.pendingToServiceIdList(newPendingMembersList))
|
||||
.map(serviceId -> RecipientId.from(serviceId))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
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.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
|
||||
@@ -30,17 +31,17 @@ public final class GroupProtoUtil {
|
||||
private GroupProtoUtil() {
|
||||
}
|
||||
|
||||
public static int findRevisionWeWereAdded(@NonNull PartialDecryptedGroup partialDecryptedGroup, @NonNull UUID uuid)
|
||||
public static int findRevisionWeWereAdded(@NonNull PartialDecryptedGroup partialDecryptedGroup, @NonNull ACI self)
|
||||
throws GroupNotAMemberException
|
||||
{
|
||||
ByteString bytes = UuidUtil.toByteString(uuid);
|
||||
ByteString bytes = self.toByteString();
|
||||
for (DecryptedMember decryptedMember : partialDecryptedGroup.getMembersList()) {
|
||||
if (decryptedMember.getUuid().equals(bytes)) {
|
||||
return decryptedMember.getJoinedAtRevision();
|
||||
}
|
||||
}
|
||||
for (DecryptedPendingMember decryptedMember : partialDecryptedGroup.getPendingMembersList()) {
|
||||
if (decryptedMember.getUuid().equals(bytes)) {
|
||||
if (decryptedMember.getServiceIdBinary().equals(bytes)) {
|
||||
// Assume latest, we don't have any information about when pending members were invited
|
||||
return partialDecryptedGroup.getRevision();
|
||||
}
|
||||
@@ -80,12 +81,12 @@ public final class GroupProtoUtil {
|
||||
|
||||
@WorkerThread
|
||||
public static Recipient pendingMemberToRecipient(@NonNull Context context, @NonNull DecryptedPendingMember pendingMember) {
|
||||
return pendingMemberServiceIdToRecipient(context, pendingMember.getUuid());
|
||||
return pendingMemberServiceIdToRecipient(context, pendingMember.getServiceIdBinary());
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static Recipient pendingMemberServiceIdToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) {
|
||||
ServiceId serviceId = ServiceId.parseOrThrow(uuidByteString);
|
||||
public static Recipient pendingMemberServiceIdToRecipient(@NonNull Context context, @NonNull ByteString serviceIdBinary) {
|
||||
ServiceId serviceId = ServiceId.parseOrThrow(serviceIdBinary);
|
||||
|
||||
if (serviceId.isUnknown()) {
|
||||
return Recipient.UNKNOWN;
|
||||
@@ -95,8 +96,8 @@ public final class GroupProtoUtil {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static @NonNull RecipientId uuidByteStringToRecipientId(@NonNull ByteString uuidByteString) {
|
||||
ServiceId serviceId = ServiceId.parseOrThrow(uuidByteString);
|
||||
public static @NonNull RecipientId serviceIdBinaryToRecipientId(@NonNull ByteString serviceIdBinary) {
|
||||
ServiceId serviceId = ServiceId.parseOrThrow(serviceIdBinary);
|
||||
|
||||
if (serviceId.isUnknown()) {
|
||||
return RecipientId.UNKNOWN;
|
||||
|
||||
@@ -126,13 +126,13 @@ public class GroupsV2Authorization {
|
||||
}
|
||||
|
||||
CallLinkAuthCredential credential = authCredentialResponse.receive(
|
||||
Recipient.self().requireServiceId().getRawUuid(),
|
||||
Recipient.self().requireAci().getLibSignalAci(),
|
||||
Instant.ofEpochSecond(todaySeconds),
|
||||
genericServerPublicParams
|
||||
);
|
||||
|
||||
return credential.present(
|
||||
Recipient.self().requireServiceId().getRawUuid(),
|
||||
Recipient.self().requireAci().getLibSignalAci(),
|
||||
Instant.ofEpochSecond(todaySeconds),
|
||||
genericServerPublicParams,
|
||||
callLinkSecretParams
|
||||
|
||||
@@ -144,7 +144,7 @@ public final class LiveGroup {
|
||||
return Transformations.map(groupRecord, g -> g.isAdmin(Recipient.self()));
|
||||
}
|
||||
|
||||
public LiveData<Set<UUID>> getBannedMembers() {
|
||||
public LiveData<Set<ServiceId>> getBannedMembers() {
|
||||
return Transformations.map(groupRecord, g -> g.isV2Group() ? g.requireV2GroupProperties().getBannedMembers() : Collections.emptySet());
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class GroupCandidateHelper {
|
||||
}
|
||||
|
||||
Optional<ExpiringProfileKeyCredential> expiringProfileKeyCredential = Optional.ofNullable(recipient.getExpiringProfileKeyCredential());
|
||||
GroupCandidate candidate = new GroupCandidate(serviceId.getRawUuid(), expiringProfileKeyCredential);
|
||||
GroupCandidate candidate = new GroupCandidate(serviceId, expiringProfileKeyCredential);
|
||||
|
||||
if (!candidate.hasValidProfileKeyCredential()) {
|
||||
recipientTable.clearProfileKeyCredential(recipient.getId());
|
||||
|
||||
+5
-9
@@ -380,9 +380,7 @@ public class GroupsV2StateProcessor {
|
||||
|
||||
boolean addedAsPendingMember = signedGroupChange.getNewPendingMembersList()
|
||||
.stream()
|
||||
.map(DecryptedPendingMember::getUuid)
|
||||
.map(UuidUtil::fromByteStringOrNull)
|
||||
.filter(Objects::nonNull)
|
||||
.map(DecryptedPendingMember::getServiceIdBinary)
|
||||
.anyMatch(serviceIds::matches);
|
||||
|
||||
boolean addedAsRequestingMember = signedGroupChange.getNewRequestingMembersList()
|
||||
@@ -398,9 +396,7 @@ public class GroupsV2StateProcessor {
|
||||
private boolean notHavingInviteRevoked(@NonNull DecryptedGroupChange signedGroupChange) {
|
||||
boolean havingInviteRevoked = signedGroupChange.getDeletePendingMembersList()
|
||||
.stream()
|
||||
.map(DecryptedPendingMemberRemoval::getUuid)
|
||||
.map(UuidUtil::fromByteStringOrNull)
|
||||
.filter(Objects::nonNull)
|
||||
.map(DecryptedPendingMemberRemoval::getServiceIdBinary)
|
||||
.anyMatch(serviceIds::matches);
|
||||
|
||||
return !havingInviteRevoked;
|
||||
@@ -434,7 +430,7 @@ public class GroupsV2StateProcessor {
|
||||
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().getRawUuid());
|
||||
int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, serviceIds.getAci());
|
||||
int logsNeededFrom = localState != null ? Math.max(localState.getRevision(), revisionWeWereAdded) : revisionWeWereAdded;
|
||||
|
||||
boolean includeFirstState = forceIncludeFirst ||
|
||||
@@ -694,7 +690,7 @@ public class GroupsV2StateProcessor {
|
||||
}
|
||||
|
||||
Optional<DecryptedMember> selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), aci.getRawUuid());
|
||||
Optional<DecryptedPendingMember> selfAsPendingOptional = DecryptedGroupUtil.findPendingByUuid(newLocalState.getPendingMembersList(), aci.getRawUuid());
|
||||
Optional<DecryptedPendingMember> selfAsPendingOptional = DecryptedGroupUtil.findPendingByServiceId(newLocalState.getPendingMembersList(), aci);
|
||||
|
||||
if (selfAsMemberOptional.isPresent()) {
|
||||
DecryptedMember selfAsMember = selfAsMemberOptional.get();
|
||||
@@ -835,7 +831,7 @@ public class GroupsV2StateProcessor {
|
||||
if (changeEditor.isPresent()) {
|
||||
return changeEditor;
|
||||
} else {
|
||||
Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), aci.getRawUuid());
|
||||
Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByServiceId(decryptedGroupV2Context.getGroupState().getPendingMembersList(), aci);
|
||||
if (pendingByUuid.isPresent()) {
|
||||
return Optional.ofNullable(UuidUtil.fromByteStringOrNull(pendingByUuid.get().getAddedByUuid()));
|
||||
}
|
||||
|
||||
+12
-6
@@ -33,6 +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;
|
||||
@@ -72,13 +73,18 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
|
||||
@NonNull DecryptedGroup decryptedGroup,
|
||||
@NonNull OutgoingMessage groupMessage)
|
||||
{
|
||||
List<UUID> memberUuids = DecryptedGroupUtil.toUuidList(decryptedGroup.getMembersList());
|
||||
List<UUID> pendingUuids = DecryptedGroupUtil.pendingToUuidList(decryptedGroup.getPendingMembersList());
|
||||
List<UUID> memberUuids = DecryptedGroupUtil.toUuidList(decryptedGroup.getMembersList());
|
||||
List<ServiceId> pendingServiceIds = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.getPendingMembersList());
|
||||
|
||||
Set<RecipientId> recipients = Stream.concat(Stream.of(memberUuids), Stream.of(pendingUuids))
|
||||
.filter(uuid -> !UuidUtil.UNKNOWN_UUID.equals(uuid))
|
||||
.filter(uuid -> !SignalStore.account().requireAci().getRawUuid().equals(uuid))
|
||||
.map(uuid -> Recipient.externalPush(ACI.from(uuid)))
|
||||
Stream<ServiceId> memberServiceIds = Stream.of(memberUuids)
|
||||
.filter(uuid -> !UuidUtil.UNKNOWN_UUID.equals(uuid))
|
||||
.filter(uuid -> !SignalStore.account().requireAci().getRawUuid().equals(uuid))
|
||||
.map(ACI::from);
|
||||
Stream<ServiceId> filteredPendingServiceIds = Stream.of(pendingServiceIds)
|
||||
.filterNot(ServiceId::isUnknown);
|
||||
|
||||
Set<RecipientId> recipients = Stream.concat(memberServiceIds, filteredPendingServiceIds)
|
||||
.map(serviceId -> Recipient.externalPush(serviceId))
|
||||
.filter(recipient -> recipient.getRegistered() != RecipientTable.RegisteredState.NOT_REGISTERED)
|
||||
.map(Recipient::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
@@ -166,19 +166,18 @@ public final class MessageGroupContext {
|
||||
return decryptedGroupV2Context.getChange();
|
||||
}
|
||||
|
||||
public @NonNull List<UUID> getAllActivePendingAndRemovedMembers() {
|
||||
LinkedList<UUID> memberUuids = new LinkedList<>();
|
||||
DecryptedGroup groupState = decryptedGroupV2Context.getGroupState();
|
||||
DecryptedGroupChange groupChange = decryptedGroupV2Context.getChange();
|
||||
public @NonNull List<ServiceId> getAllActivePendingAndRemovedMembers() {
|
||||
DecryptedGroup groupState = decryptedGroupV2Context.getGroupState();
|
||||
DecryptedGroupChange groupChange = decryptedGroupV2Context.getChange();
|
||||
|
||||
memberUuids.addAll(DecryptedGroupUtil.membersToUuidList(groupState.getMembersList()));
|
||||
memberUuids.addAll(DecryptedGroupUtil.pendingToUuidList(groupState.getPendingMembersList()));
|
||||
|
||||
memberUuids.addAll(DecryptedGroupUtil.removedMembersUuidList(groupChange));
|
||||
memberUuids.addAll(DecryptedGroupUtil.removedPendingMembersUuidList(groupChange));
|
||||
memberUuids.addAll(DecryptedGroupUtil.removedRequestingMembersUuidList(groupChange));
|
||||
|
||||
return UuidUtil.filterKnown(memberUuids);
|
||||
return Stream.of(DecryptedGroupUtil.membersToServiceIdList(groupState.getMembersList()),
|
||||
DecryptedGroupUtil.pendingToServiceIdList(groupState.getPendingMembersList()),
|
||||
DecryptedGroupUtil.removedMembersServiceIdList(groupChange),
|
||||
DecryptedGroupUtil.removedPendingMembersServiceIdList(groupChange),
|
||||
DecryptedGroupUtil.removedRequestingMembersServiceIdList(groupChange))
|
||||
.flatMap(Stream::of)
|
||||
.filterNot(ServiceId::isUnknown)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -45,7 +45,7 @@ class SignalCallLinkManager(
|
||||
linkRootKey: ByteArray,
|
||||
roomId: ByteArray
|
||||
): CreateCallLinkCredentialPresentation {
|
||||
val userUuid = Recipient.self().requireAci().rawUuid
|
||||
val userAci = Recipient.self().requireAci()
|
||||
val requestContext = CreateCallLinkCredentialRequestContext.forRoom(roomId)
|
||||
val request = requestContext.request
|
||||
|
||||
@@ -60,7 +60,7 @@ class SignalCallLinkManager(
|
||||
|
||||
val createCallLinkCredential: CreateCallLinkCredential = requestContext.receiveResponse(
|
||||
serviceResponse.result.get(),
|
||||
userUuid,
|
||||
userAci.libSignalAci,
|
||||
genericServerPublicParams
|
||||
)
|
||||
|
||||
@@ -68,7 +68,7 @@ class SignalCallLinkManager(
|
||||
|
||||
return createCallLinkCredential.present(
|
||||
roomId,
|
||||
userUuid,
|
||||
userAci.libSignalAci,
|
||||
genericServerPublicParams,
|
||||
CallLinkSecretParams.deriveFromRootKey(linkRootKey)
|
||||
)
|
||||
|
||||
@@ -295,7 +295,7 @@ public final class ProfileUtil {
|
||||
Log.i(TAG, String.format("Updating profile key credential on recipient %s, fetching", recipient.getId()));
|
||||
|
||||
Optional<ExpiringProfileKeyCredential> profileKeyCredentialOptional = ApplicationDependencies.getSignalServiceAccountManager()
|
||||
.resolveProfileKeyCredential(recipient.requireServiceId(), profileKey, Locale.getDefault());
|
||||
.resolveProfileKeyCredential(recipient.requireAci(), profileKey, Locale.getDefault());
|
||||
|
||||
if (profileKeyCredentialOptional.isPresent()) {
|
||||
boolean updatedProfileKey = SignalDatabase.recipients().setProfileKeyCredential(recipient.getId(), profileKey, profileKeyCredentialOptional.get());
|
||||
|
||||
@@ -29,9 +29,9 @@ object GV2Transformer : ColumnTransformer {
|
||||
|
||||
private fun DecryptedGroup.formatAsHtml(): String {
|
||||
val members: String = describeList(membersList, DecryptedMember::getUuid)
|
||||
val pending: String = describeList(pendingMembersList, DecryptedPendingMember::getUuid)
|
||||
val pending: String = describeList(pendingMembersList, DecryptedPendingMember::getServiceIdBinary)
|
||||
val requesting: String = describeList(requestingMembersList, DecryptedRequestingMember::getUuid)
|
||||
val banned: String = describeList(bannedMembersList, DecryptedBannedMember::getUuid)
|
||||
val banned: String = describeList(bannedMembersList, DecryptedBannedMember::getServiceIdBinary)
|
||||
|
||||
return """
|
||||
Revision: $revision
|
||||
|
||||
@@ -85,15 +85,15 @@ class GroupChangeData(private val revision: Int, private val groupOperations: Gr
|
||||
}
|
||||
|
||||
fun source(serviceId: ServiceId) {
|
||||
actionsBuilder.sourceUuid = groupOperations.encryptUuid(serviceId.rawUuid)
|
||||
actionsBuilder.sourceUuid = groupOperations.encryptServiceId(serviceId)
|
||||
}
|
||||
|
||||
fun deleteMember(serviceId: ServiceId) {
|
||||
actionsBuilder.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(groupOperations.encryptUuid(serviceId.rawUuid)))
|
||||
actionsBuilder.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(groupOperations.encryptServiceId(serviceId)))
|
||||
}
|
||||
|
||||
fun modifyRole(serviceId: ServiceId, role: Member.Role) {
|
||||
actionsBuilder.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(groupOperations.encryptUuid(serviceId.rawUuid)).setRole(role))
|
||||
actionsBuilder.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(groupOperations.encryptServiceId(serviceId)).setRole(role))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1475,7 +1475,7 @@ public final class GroupsV2UpdateMessageProducerTest {
|
||||
|
||||
GroupStateBuilder invite(@NonNull UUID inviter, @NonNull UUID invitee) {
|
||||
builder.addPendingMembers(DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(invitee))
|
||||
.setServiceIdBinary(UuidUtil.toByteString(invitee))
|
||||
.setAddedByUuid(UuidUtil.toByteString(inviter)));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -85,14 +85,14 @@ public final class ChangeBuilder {
|
||||
|
||||
public ChangeBuilder inviteBy(@NonNull UUID potentialMember, @NonNull UUID inviter) {
|
||||
builder.addNewPendingMembers(DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(potentialMember))
|
||||
.setServiceIdBinary(UuidUtil.toByteString(potentialMember))
|
||||
.setAddedByUuid(UuidUtil.toByteString(inviter)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChangeBuilder uninvite(@NonNull UUID pendingMember) {
|
||||
builder.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(pendingMember)));
|
||||
.setServiceIdBinary(UuidUtil.toByteString(pendingMember)));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+1
-6
@@ -9,7 +9,6 @@ import org.signal.storageservice.protos.groups.local.DecryptedPendingMember
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
|
||||
import java.util.UUID
|
||||
|
||||
@@ -43,10 +42,6 @@ fun DecryptedGroupChange.Builder.addMember(aci: ACI) {
|
||||
addNewMembers(member(aci))
|
||||
}
|
||||
|
||||
fun ServiceId.toByteString(): ByteString {
|
||||
return UuidUtil.toByteString(rawUuid)
|
||||
}
|
||||
|
||||
fun member(serviceId: UUID, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember {
|
||||
return member(ACI.from(serviceId), role, joinedAt)
|
||||
}
|
||||
@@ -67,6 +62,6 @@ fun requestingMember(serviceId: ServiceId): DecryptedRequestingMember {
|
||||
|
||||
fun pendingMember(serviceId: ServiceId): DecryptedPendingMember {
|
||||
return DecryptedPendingMember.newBuilder()
|
||||
.setUuid(serviceId.toByteString())
|
||||
.setServiceIdBinary(serviceId.toByteString())
|
||||
.build()
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ dependencyResolutionManagement {
|
||||
version('exoplayer', '2.19.0')
|
||||
version('glide', '4.13.2')
|
||||
version('kotlin', '1.8.10')
|
||||
version('libsignal-client', '0.28.1')
|
||||
version('libsignal-client', '0.30.0')
|
||||
version('mp4parser', '1.9.39')
|
||||
version('android-gradle-plugin', '8.0.2')
|
||||
version('accompanist', '0.28.0')
|
||||
|
||||
@@ -4992,44 +4992,20 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="6eb4422e8a618b3b76cb2096a3619d251f9e27989dc68307a1e5414c3710f2d1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.signal" name="libsignal-android" version="0.26.0">
|
||||
<artifact name="libsignal-android-0.26.0.aar">
|
||||
<sha256 value="5d402e4a4cccf98feab0876470f3adb71f442e25935ccf5214f8dc0d1fb9386f" origin="Generated by Gradle"/>
|
||||
<component group="org.signal" name="libsignal-android" version="0.30.0">
|
||||
<artifact name="libsignal-android-0.30.0.aar">
|
||||
<sha256 value="213bbe44b9fb82aa07a2a7dff76c52cc8f20c21652f4e48e2b9592ea10fd9858" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="libsignal-android-0.26.0.module">
|
||||
<sha256 value="87dd9d3fd15280aef8935b3230d891198596d7cfd0567a324a335f700fdf85c1" origin="Generated by Gradle"/>
|
||||
<artifact name="libsignal-android-0.30.0.module">
|
||||
<sha256 value="9e91e6702832b6f08535e836c7f14d927c08b407fb0be771bc15959a120e0d29" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.signal" name="libsignal-android" version="0.28.0">
|
||||
<artifact name="libsignal-android-0.28.0.aar">
|
||||
<sha256 value="2af4b218de5169850419711f2c104ac922e5a63bac9bae0681cae1ff63dbf058" origin="Generated by Gradle"/>
|
||||
<component group="org.signal" name="libsignal-client" version="0.30.0">
|
||||
<artifact name="libsignal-client-0.30.0.jar">
|
||||
<sha256 value="12366d110077890bc5a559928b3b967a00493ea60658d8e67a7d5d42729507b1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="libsignal-android-0.28.0.module">
|
||||
<sha256 value="0989ae0a1824d4ee1887256de0f2970fe610341b1184936fc346ee0d6888e45b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.signal" name="libsignal-android" version="0.28.1">
|
||||
<artifact name="libsignal-android-0.28.1.aar">
|
||||
<sha256 value="05972a90762e901b09d016f3e47e731d9e02526cb2a2486b9838f1a544fbedec" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="libsignal-android-0.28.1.module">
|
||||
<sha256 value="cff292584d0aa3df68d202db382239f8574693cacbbe5accc2b51bbd7f510fd2" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.signal" name="libsignal-client" version="0.26.0">
|
||||
<artifact name="libsignal-client-0.26.0.jar">
|
||||
<sha256 value="1493199648838b14c27b1c9d4a8ccd42c777dd7f9ec46d509f6aae0db0ac95db" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="libsignal-client-0.26.0.module">
|
||||
<sha256 value="c315752e06dc156184e95062ed0696582720af41d09d0ce25344aa50f7d8f6d6" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.signal" name="libsignal-client" version="0.28.1">
|
||||
<artifact name="libsignal-client-0.28.1.jar">
|
||||
<sha256 value="6df1dfb402e078ca84c4c14d220afead68a94c5c79aa0f360f7b999c768cb7f2" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="libsignal-client-0.28.1.module">
|
||||
<sha256 value="4c14e7476612ea598e806834ac47fa461555efa5f9c859a445905ca27d20769a" origin="Generated by Gradle"/>
|
||||
<artifact name="libsignal-client-0.30.0.module">
|
||||
<sha256 value="6392d6b1fa1823d45f2ebfa5c5619fe96c3393826e66e5d7127efe2b5844e0fb" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="org.signal" name="ringrtc-android" version="2.30.0">
|
||||
|
||||
+4
-4
@@ -740,23 +740,23 @@ public class SignalServiceAccountManager {
|
||||
new ProfileCipherOutputStreamFactory(profileKey));
|
||||
}
|
||||
|
||||
return this.pushServiceSocket.writeProfile(new SignalServiceProfileWrite(profileKey.getProfileKeyVersion(aci.getRawUuid()).serialize(),
|
||||
return this.pushServiceSocket.writeProfile(new SignalServiceProfileWrite(profileKey.getProfileKeyVersion(aci.getLibSignalAci()).serialize(),
|
||||
ciphertextName,
|
||||
ciphertextAbout,
|
||||
ciphertextEmoji,
|
||||
ciphertextMobileCoinAddress,
|
||||
avatar.hasAvatar,
|
||||
avatar.keepTheSame,
|
||||
profileKey.getCommitment(aci.getRawUuid()).serialize(),
|
||||
profileKey.getCommitment(aci.getLibSignalAci()).serialize(),
|
||||
visibleBadgeIds),
|
||||
profileAvatarData);
|
||||
}
|
||||
|
||||
public Optional<ExpiringProfileKeyCredential> resolveProfileKeyCredential(ServiceId serviceId, ProfileKey profileKey, Locale locale)
|
||||
public Optional<ExpiringProfileKeyCredential> resolveProfileKeyCredential(ACI serviceId, ProfileKey profileKey, Locale locale)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException
|
||||
{
|
||||
try {
|
||||
ProfileAndCredential credential = this.pushServiceSocket.retrieveVersionedProfileAndCredential(serviceId.getRawUuid(), profileKey, Optional.empty(), locale).get(10, TimeUnit.SECONDS);
|
||||
ProfileAndCredential credential = this.pushServiceSocket.retrieveVersionedProfileAndCredential(serviceId, profileKey, Optional.empty(), locale).get(10, TimeUnit.SECONDS);
|
||||
return credential.getExpiringProfileKeyCredential();
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
throw new PushNetworkException(e);
|
||||
|
||||
+15
-4
@@ -20,6 +20,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStickerManifes
|
||||
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
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.push.exceptions.MissingConfigurationException;
|
||||
import org.whispersystems.signalservice.api.util.CredentialsProvider;
|
||||
@@ -34,6 +35,7 @@ import org.whispersystems.signalservice.internal.sticker.StickerProtos;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
import org.whispersystems.signalservice.internal.util.concurrent.FutureTransformers;
|
||||
import org.whispersystems.signalservice.internal.util.concurrent.ListenableFuture;
|
||||
import org.whispersystems.signalservice.internal.util.concurrent.SettableFuture;
|
||||
import org.whispersystems.signalservice.internal.websocket.ResponseMapper;
|
||||
|
||||
import java.io.File;
|
||||
@@ -96,13 +98,22 @@ public class SignalServiceMessageReceiver {
|
||||
SignalServiceProfile.RequestType requestType,
|
||||
Locale locale)
|
||||
{
|
||||
ServiceId serviceId = address.getServiceId();
|
||||
|
||||
if (profileKey.isPresent()) {
|
||||
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
|
||||
return socket.retrieveVersionedProfileAndCredential(serviceId.getRawUuid(), profileKey.get(), unidentifiedAccess, locale);
|
||||
ACI aci;
|
||||
if (address.getServiceId() instanceof ACI) {
|
||||
aci = (ACI) address.getServiceId();
|
||||
} else {
|
||||
return FutureTransformers.map(socket.retrieveVersionedProfile(serviceId.getRawUuid(), profileKey.get(), unidentifiedAccess, locale), profile -> {
|
||||
// We shouldn't ever have a profile key for a non-ACI.
|
||||
SettableFuture<ProfileAndCredential> result = new SettableFuture<>();
|
||||
result.setException(new ClassCastException("retrieving a versioned profile requires an ACI"));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
|
||||
return socket.retrieveVersionedProfileAndCredential(aci, profileKey.get(), unidentifiedAccess, locale);
|
||||
} else {
|
||||
return FutureTransformers.map(socket.retrieveVersionedProfile(aci, profileKey.get(), unidentifiedAccess, locale), profile -> {
|
||||
return new ProfileAndCredential(profile,
|
||||
SignalServiceProfile.RequestType.PROFILE,
|
||||
Optional.empty());
|
||||
|
||||
+64
-71
@@ -15,6 +15,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemoval;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
|
||||
import org.signal.storageservice.protos.groups.local.EnabledState;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.ServiceIds;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
@@ -28,6 +29,8 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class DecryptedGroupUtil {
|
||||
|
||||
private static final String TAG = DecryptedGroupUtil.class.getSimpleName();
|
||||
@@ -42,18 +45,18 @@ public final class DecryptedGroupUtil {
|
||||
return uuidList;
|
||||
}
|
||||
|
||||
public static ArrayList<UUID> membersToUuidList(Collection<DecryptedMember> membersList) {
|
||||
ArrayList<UUID> uuidList = new ArrayList<>(membersList.size());
|
||||
public static ArrayList<ServiceId> membersToServiceIdList(Collection<DecryptedMember> membersList) {
|
||||
ArrayList<ServiceId> serviceIdList = new ArrayList<>(membersList.size());
|
||||
|
||||
for (DecryptedMember member : membersList) {
|
||||
UUID uuid = toUuid(member);
|
||||
ServiceId serviceId = ServiceId.parseOrNull(member.getUuid());
|
||||
|
||||
if (!UuidUtil.UNKNOWN_UUID.equals(uuid)) {
|
||||
uuidList.add(uuid);
|
||||
if (serviceId != null) {
|
||||
serviceIdList.add(serviceId);
|
||||
}
|
||||
}
|
||||
|
||||
return uuidList;
|
||||
return serviceIdList;
|
||||
}
|
||||
|
||||
public static Set<ByteString> membersToUuidByteStringSet(Collection<DecryptedMember> membersList) {
|
||||
@@ -67,98 +70,94 @@ public final class DecryptedGroupUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Can return non-decryptable member UUIDs as {@link UuidUtil#UNKNOWN_UUID}.
|
||||
* Can return non-decryptable member UUIDs as unknown ACIs.
|
||||
*/
|
||||
public static ArrayList<UUID> pendingToUuidList(Collection<DecryptedPendingMember> membersList) {
|
||||
ArrayList<UUID> uuidList = new ArrayList<>(membersList.size());
|
||||
public static ArrayList<ServiceId> pendingToServiceIdList(Collection<DecryptedPendingMember> membersList) {
|
||||
ArrayList<ServiceId> serviceIdList = new ArrayList<>(membersList.size());
|
||||
|
||||
for (DecryptedPendingMember member : membersList) {
|
||||
uuidList.add(toUuid(member));
|
||||
ServiceId serviceId = ServiceId.parseOrNull(member.getServiceIdBinary());
|
||||
if (serviceId != null) {
|
||||
serviceIdList.add(serviceId);
|
||||
} else {
|
||||
serviceIdList.add(ServiceId.ACI.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
return uuidList;
|
||||
return serviceIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will not return any non-decryptable member UUIDs.
|
||||
*/
|
||||
public static ArrayList<UUID> removedMembersUuidList(DecryptedGroupChange groupChange) {
|
||||
List<ByteString> deletedMembers = groupChange.getDeleteMembersList();
|
||||
ArrayList<UUID> uuidList = new ArrayList<>(deletedMembers.size());
|
||||
public static ArrayList<ServiceId> removedMembersServiceIdList(DecryptedGroupChange groupChange) {
|
||||
List<ByteString> deletedMembers = groupChange.getDeleteMembersList();
|
||||
ArrayList<ServiceId> serviceIdList = new ArrayList<>(deletedMembers.size());
|
||||
|
||||
for (ByteString member : deletedMembers) {
|
||||
UUID uuid = toUuid(member);
|
||||
ServiceId serviceId = ServiceId.parseOrNull(member);
|
||||
|
||||
if (!UuidUtil.UNKNOWN_UUID.equals(uuid)) {
|
||||
uuidList.add(uuid);
|
||||
if (serviceId != null) {
|
||||
serviceIdList.add(serviceId);
|
||||
}
|
||||
}
|
||||
|
||||
return uuidList;
|
||||
return serviceIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will not return any non-decryptable member UUIDs.
|
||||
*/
|
||||
public static ArrayList<UUID> removedPendingMembersUuidList(DecryptedGroupChange groupChange) {
|
||||
public static ArrayList<ServiceId> removedPendingMembersServiceIdList(DecryptedGroupChange groupChange) {
|
||||
List<DecryptedPendingMemberRemoval> deletedPendingMembers = groupChange.getDeletePendingMembersList();
|
||||
ArrayList<UUID> uuidList = new ArrayList<>(deletedPendingMembers.size());
|
||||
ArrayList<ServiceId> serviceIdList = new ArrayList<>(deletedPendingMembers.size());
|
||||
|
||||
for (DecryptedPendingMemberRemoval member : deletedPendingMembers) {
|
||||
UUID uuid = toUuid(member.getUuid());
|
||||
ServiceId serviceId = ServiceId.parseOrNull(member.getServiceIdBinary());
|
||||
|
||||
if(!UuidUtil.UNKNOWN_UUID.equals(uuid)) {
|
||||
uuidList.add(uuid);
|
||||
if(serviceId != null) {
|
||||
serviceIdList.add(serviceId);
|
||||
}
|
||||
}
|
||||
|
||||
return uuidList;
|
||||
return serviceIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will not return any non-decryptable member UUIDs.
|
||||
*/
|
||||
public static ArrayList<UUID> removedRequestingMembersUuidList(DecryptedGroupChange groupChange) {
|
||||
List<ByteString> deleteRequestingMembers = groupChange.getDeleteRequestingMembersList();
|
||||
ArrayList<UUID> uuidList = new ArrayList<>(deleteRequestingMembers.size());
|
||||
public static ArrayList<ServiceId> removedRequestingMembersServiceIdList(DecryptedGroupChange groupChange) {
|
||||
List<ByteString> deleteRequestingMembers = groupChange.getDeleteRequestingMembersList();
|
||||
ArrayList<ServiceId> serviceIdList = new ArrayList<>(deleteRequestingMembers.size());
|
||||
|
||||
for (ByteString member : deleteRequestingMembers) {
|
||||
UUID uuid = toUuid(member);
|
||||
ServiceId serviceId = ServiceId.parseOrNull(member);
|
||||
|
||||
if(!UuidUtil.UNKNOWN_UUID.equals(uuid)) {
|
||||
uuidList.add(uuid);
|
||||
if(serviceId != null) {
|
||||
serviceIdList.add(serviceId);
|
||||
}
|
||||
}
|
||||
|
||||
return uuidList;
|
||||
return serviceIdList;
|
||||
}
|
||||
|
||||
public static Set<UUID> bannedMembersToUuidSet(Collection<DecryptedBannedMember> membersList) {
|
||||
Set<UUID> uuidSet = new HashSet<>(membersList.size());
|
||||
public static Set<ServiceId> bannedMembersToServiceIdSet(Collection<DecryptedBannedMember> membersList) {
|
||||
Set<ServiceId> serviceIdSet = new HashSet<>(membersList.size());
|
||||
|
||||
for (DecryptedBannedMember member : membersList) {
|
||||
UUID uuid = toUuid(member);
|
||||
|
||||
if (!UuidUtil.UNKNOWN_UUID.equals(uuid)) {
|
||||
uuidSet.add(uuid);
|
||||
ServiceId serviceId = ServiceId.parseOrNull(member.getServiceIdBinary());
|
||||
if (serviceId != null) {
|
||||
serviceIdSet.add(serviceId);
|
||||
}
|
||||
}
|
||||
|
||||
return uuidSet;
|
||||
return serviceIdSet;
|
||||
}
|
||||
|
||||
public static UUID toUuid(DecryptedMember member) {
|
||||
return toUuid(member.getUuid());
|
||||
}
|
||||
|
||||
public static UUID toUuid(DecryptedPendingMember member) {
|
||||
return toUuid(member.getUuid());
|
||||
}
|
||||
|
||||
public static UUID toUuid(DecryptedBannedMember member) {
|
||||
return toUuid(member.getUuid());
|
||||
}
|
||||
|
||||
private static UUID toUuid(ByteString memberUuid) {
|
||||
return UuidUtil.fromByteStringOrUnknown(memberUuid);
|
||||
}
|
||||
@@ -182,11 +181,11 @@ public final class DecryptedGroupUtil {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static Optional<DecryptedPendingMember> findPendingByUuid(Collection<DecryptedPendingMember> members, UUID uuid) {
|
||||
ByteString uuidBytes = UuidUtil.toByteString(uuid);
|
||||
public static Optional<DecryptedPendingMember> findPendingByServiceId(Collection<DecryptedPendingMember> members, ServiceId serviceId) {
|
||||
ByteString serviceIdBinary = serviceId.toByteString();
|
||||
|
||||
for (DecryptedPendingMember member : members) {
|
||||
if (uuidBytes.equals(member.getUuid())) {
|
||||
if (serviceIdBinary.equals(member.getServiceIdBinary())) {
|
||||
return Optional.of(member);
|
||||
}
|
||||
}
|
||||
@@ -196,7 +195,7 @@ public final class DecryptedGroupUtil {
|
||||
|
||||
public static Optional<DecryptedPendingMember> findPendingByServiceIds(Collection<DecryptedPendingMember> members, ServiceIds serviceIds) {
|
||||
for (DecryptedPendingMember member : members) {
|
||||
if (serviceIds.matches(member.getUuid())) {
|
||||
if (serviceIds.matches(member.getServiceIdBinary())) {
|
||||
return Optional.of(member);
|
||||
}
|
||||
}
|
||||
@@ -215,10 +214,10 @@ public final class DecryptedGroupUtil {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int findPendingIndexByUuid(List<DecryptedPendingMember> members, ByteString uuid) {
|
||||
private static int findPendingIndexByServiceId(List<DecryptedPendingMember> members, ByteString serviceIdBinary) {
|
||||
for (int i = 0; i < members.size(); i++) {
|
||||
DecryptedPendingMember member = members.get(i);
|
||||
if (uuid.equals(member.getUuid())) {
|
||||
if (serviceIdBinary.equals(member.getServiceIdBinary())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -416,7 +415,7 @@ public final class DecryptedGroupUtil {
|
||||
Set<ByteString> pendingMemberCipherTexts = getPendingMemberCipherTextSet(builder.getPendingMembersList());
|
||||
|
||||
for (DecryptedPendingMember pendingMember : newPendingMembersList) {
|
||||
if (fullMemberSet.contains(pendingMember.getUuid())) {
|
||||
if (fullMemberSet.contains(pendingMember.getServiceIdBinary())) {
|
||||
throw new NotAbleToApplyGroupV2ChangeException();
|
||||
}
|
||||
|
||||
@@ -441,7 +440,7 @@ public final class DecryptedGroupUtil {
|
||||
|
||||
protected static void applyPromotePendingMemberActions(DecryptedGroup.Builder builder, List<DecryptedMember> promotePendingMembersList) throws NotAbleToApplyGroupV2ChangeException {
|
||||
for (DecryptedMember newMember : promotePendingMembersList) {
|
||||
int index = findPendingIndexByUuid(builder.getPendingMembersList(), newMember.getUuid());
|
||||
int index = findPendingIndexByServiceId(builder.getPendingMembersList(), newMember.getUuid());
|
||||
|
||||
if (index == -1) {
|
||||
throw new NotAbleToApplyGroupV2ChangeException();
|
||||
@@ -556,10 +555,10 @@ public final class DecryptedGroupUtil {
|
||||
}
|
||||
|
||||
private static void applyAddBannedMembersActions(DecryptedGroup.Builder builder, List<DecryptedBannedMember> newBannedMembersList) {
|
||||
Set<ByteString> bannedMemberUuidSet = getBannedMemberUuidSet(builder.getBannedMembersList());
|
||||
Set<ByteString> bannedMemberServiceIdSet = getBannedMemberServiceIdSet(builder.getBannedMembersList());
|
||||
|
||||
for (DecryptedBannedMember member : newBannedMembersList) {
|
||||
if (bannedMemberUuidSet.contains(member.getUuid())) {
|
||||
if (bannedMemberServiceIdSet.contains(member.getServiceIdBinary())) {
|
||||
Log.w(TAG, "Banned member already in banned list");
|
||||
} else {
|
||||
builder.addBannedMembers(member);
|
||||
@@ -569,7 +568,7 @@ public final class DecryptedGroupUtil {
|
||||
|
||||
private static void applyDeleteBannedMembersActions(DecryptedGroup.Builder builder, List<DecryptedBannedMember> deleteMembersList) {
|
||||
for (DecryptedBannedMember removedMember : deleteMembersList) {
|
||||
int index = indexOfUuidInBannedMemberList(builder.getBannedMembersList(), removedMember.getUuid());
|
||||
int index = indexOfServiceIdInBannedMemberList(builder.getBannedMembersList(), removedMember.getServiceIdBinary());
|
||||
|
||||
if (index == -1) {
|
||||
Log.w(TAG, "Deleted banned member on change not found in banned list");
|
||||
@@ -582,7 +581,7 @@ public final class DecryptedGroupUtil {
|
||||
|
||||
protected static void applyPromotePendingPniAciMemberActions(DecryptedGroup.Builder builder, List<DecryptedMember> promotePendingPniAciMembersList) throws NotAbleToApplyGroupV2ChangeException {
|
||||
for (DecryptedMember newMember : promotePendingPniAciMembersList) {
|
||||
int index = findPendingIndexByUuid(builder.getPendingMembersList(), newMember.getPni());
|
||||
int index = findPendingIndexByServiceId(builder.getPendingMembersList(), newMember.getPni());
|
||||
|
||||
if (index == -1) {
|
||||
throw new NotAbleToApplyGroupV2ChangeException();
|
||||
@@ -619,14 +618,14 @@ public final class DecryptedGroupUtil {
|
||||
return pendingMemberCipherTexts;
|
||||
}
|
||||
|
||||
private static Set<ByteString> getBannedMemberUuidSet(List<DecryptedBannedMember> bannedMemberList) {
|
||||
Set<ByteString> memberUuids = new HashSet<>(bannedMemberList.size());
|
||||
private static Set<ByteString> getBannedMemberServiceIdSet(List<DecryptedBannedMember> bannedMemberList) {
|
||||
Set<ByteString> memberServiceIds = new HashSet<>(bannedMemberList.size());
|
||||
|
||||
for (DecryptedBannedMember member : bannedMemberList) {
|
||||
memberUuids.add(member.getUuid());
|
||||
memberServiceIds.add(member.getServiceIdBinary());
|
||||
}
|
||||
|
||||
return memberUuids;
|
||||
return memberServiceIds;
|
||||
}
|
||||
|
||||
private static void removePendingAndRequestingMembersNowInGroup(DecryptedGroup.Builder builder) {
|
||||
@@ -634,7 +633,7 @@ public final class DecryptedGroupUtil {
|
||||
|
||||
for (int i = builder.getPendingMembersCount() - 1; i >= 0; i--) {
|
||||
DecryptedPendingMember pendingMember = builder.getPendingMembers(i);
|
||||
if (allMembers.contains(pendingMember.getUuid())) {
|
||||
if (allMembers.contains(pendingMember.getServiceIdBinary())) {
|
||||
builder.removePendingMembers(i);
|
||||
}
|
||||
}
|
||||
@@ -667,19 +666,13 @@ public final class DecryptedGroupUtil {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int indexOfUuidInBannedMemberList(List<DecryptedBannedMember> memberList, ByteString uuid) {
|
||||
private static int indexOfServiceIdInBannedMemberList(List<DecryptedBannedMember> memberList, ByteString serviceIdBinary) {
|
||||
for (int i = 0; i < memberList.size(); i++) {
|
||||
if (uuid.equals(memberList.get(i).getUuid())) return i;
|
||||
if (serviceIdBinary.equals(memberList.get(i).getServiceIdBinary())) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static Optional<UUID> findInviter(List<DecryptedPendingMember> pendingMembersList, UUID uuid) {
|
||||
return Optional.ofNullable(findPendingByUuid(pendingMembersList, uuid).map(DecryptedPendingMember::getAddedByUuid)
|
||||
.map(UuidUtil::fromByteStringOrNull)
|
||||
.orElse(null));
|
||||
}
|
||||
|
||||
public static boolean changeIsEmpty(DecryptedGroupChange change) {
|
||||
return change.getModifiedProfileKeysCount() == 0 && // field 6
|
||||
changeIsEmptyExceptForProfileKeyChanges(change);
|
||||
|
||||
+11
-11
@@ -1,12 +1,12 @@
|
||||
package org.whispersystems.signalservice.api.groupsv2;
|
||||
|
||||
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.util.ExpiringProfileCredentialUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents a potential new member of a group.
|
||||
@@ -15,20 +15,20 @@ import java.util.UUID;
|
||||
* <p>
|
||||
* If it does not, then this user can only be invited.
|
||||
* <p>
|
||||
* Equality by UUID only used to makes sure Sets only contain one copy.
|
||||
* Equality by ServiceId only used to makes sure Sets only contain one copy.
|
||||
*/
|
||||
public final class GroupCandidate {
|
||||
|
||||
private final UUID uuid;
|
||||
private final ServiceId serviceId;
|
||||
private final Optional<ExpiringProfileKeyCredential> expiringProfileKeyCredential;
|
||||
|
||||
public GroupCandidate(UUID uuid, Optional<ExpiringProfileKeyCredential> expiringProfileKeyCredential) {
|
||||
this.uuid = uuid;
|
||||
public GroupCandidate(ServiceId serviceId, Optional<ExpiringProfileKeyCredential> expiringProfileKeyCredential) {
|
||||
this.serviceId = serviceId;
|
||||
this.expiringProfileKeyCredential = expiringProfileKeyCredential;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
public ServiceId getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public Optional<ExpiringProfileKeyCredential> getExpiringProfileKeyCredential() {
|
||||
@@ -57,12 +57,12 @@ public final class GroupCandidate {
|
||||
}
|
||||
|
||||
public GroupCandidate withoutExpiringProfileKeyCredential() {
|
||||
return expiringProfileKeyCredential.isPresent() ? new GroupCandidate(uuid, Optional.empty())
|
||||
return expiringProfileKeyCredential.isPresent() ? new GroupCandidate(serviceId, Optional.empty())
|
||||
: this;
|
||||
}
|
||||
|
||||
public GroupCandidate withExpiringProfileKeyCredential(ExpiringProfileKeyCredential expiringProfileKeyCredential) {
|
||||
return new GroupCandidate(uuid, Optional.of(expiringProfileKeyCredential));
|
||||
return new GroupCandidate(serviceId, Optional.of(expiringProfileKeyCredential));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,11 +72,11 @@ public final class GroupCandidate {
|
||||
}
|
||||
|
||||
GroupCandidate other = (GroupCandidate) obj;
|
||||
return other.uuid == uuid;
|
||||
return other.serviceId.equals(serviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return uuid.hashCode();
|
||||
return serviceId.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
+37
-37
@@ -60,30 +60,30 @@ public final class GroupChangeReconstruct {
|
||||
Set<ByteString> fromStateMemberUuids = membersToSetOfUuids(fromState.getMembersList());
|
||||
Set<ByteString> toStateMemberUuids = membersToSetOfUuids(toState.getMembersList());
|
||||
|
||||
Set<ByteString> pendingMembersListA = pendingMembersToSetOfUuids(fromState.getPendingMembersList());
|
||||
Set<ByteString> pendingMembersListB = pendingMembersToSetOfUuids(toState.getPendingMembersList());
|
||||
Set<ByteString> pendingMembersListA = pendingMembersToSetOfServiceIds(fromState.getPendingMembersList());
|
||||
Set<ByteString> pendingMembersListB = pendingMembersToSetOfServiceIds(toState.getPendingMembersList());
|
||||
|
||||
Set<ByteString> requestingMembersListA = requestingMembersToSetOfUuids(fromState.getRequestingMembersList());
|
||||
Set<ByteString> requestingMembersListB = requestingMembersToSetOfUuids(toState.getRequestingMembersList());
|
||||
|
||||
Set<ByteString> bannedMembersListA = bannedMembersToSetOfUuids(fromState.getBannedMembersList());
|
||||
Set<ByteString> bannedMembersListB = bannedMembersToSetOfUuids(toState.getBannedMembersList());
|
||||
Set<ByteString> bannedMembersListA = bannedMembersToSetOfServiceIds(fromState.getBannedMembersList());
|
||||
Set<ByteString> bannedMembersListB = bannedMembersToSetOfServiceIds(toState.getBannedMembersList());
|
||||
|
||||
Set<ByteString> removedPendingMemberUuids = subtract(pendingMembersListA, pendingMembersListB);
|
||||
Set<ByteString> removedRequestingMemberUuids = subtract(requestingMembersListA, requestingMembersListB);
|
||||
Set<ByteString> newPendingMemberUuids = subtract(pendingMembersListB, pendingMembersListA);
|
||||
Set<ByteString> newRequestingMemberUuids = subtract(requestingMembersListB, requestingMembersListA);
|
||||
Set<ByteString> removedMemberUuids = subtract(fromStateMemberUuids, toStateMemberUuids);
|
||||
Set<ByteString> newMemberUuids = subtract(toStateMemberUuids, fromStateMemberUuids);
|
||||
Set<ByteString> removedBannedMemberUuids = subtract(bannedMembersListA, bannedMembersListB);
|
||||
Set<ByteString> newBannedMemberUuids = subtract(bannedMembersListB, bannedMembersListA);
|
||||
Set<ByteString> removedPendingMemberServiceIds = subtract(pendingMembersListA, pendingMembersListB);
|
||||
Set<ByteString> removedRequestingMemberUuids = subtract(requestingMembersListA, requestingMembersListB);
|
||||
Set<ByteString> newPendingMemberServiceIds = subtract(pendingMembersListB, pendingMembersListA);
|
||||
Set<ByteString> newRequestingMemberUuids = subtract(requestingMembersListB, requestingMembersListA);
|
||||
Set<ByteString> removedMemberUuids = subtract(fromStateMemberUuids, toStateMemberUuids);
|
||||
Set<ByteString> newMemberUuids = subtract(toStateMemberUuids, fromStateMemberUuids);
|
||||
Set<ByteString> removedBannedMemberServiceIds = subtract(bannedMembersListA, bannedMembersListB);
|
||||
Set<ByteString> newBannedMemberServiceIds = subtract(bannedMembersListB, bannedMembersListA);
|
||||
|
||||
Set<ByteString> addedByInvitationUuids = intersect(newMemberUuids, removedPendingMemberUuids);
|
||||
Set<ByteString> addedByInvitationUuids = intersect(newMemberUuids, removedPendingMemberServiceIds);
|
||||
Set<ByteString> addedByRequestApprovalUuids = intersect(newMemberUuids, removedRequestingMemberUuids);
|
||||
Set<DecryptedMember> addedMembersByInvitation = intersectByUUID(toState.getMembersList(), addedByInvitationUuids);
|
||||
Set<DecryptedMember> addedMembersByRequestApproval = intersectByUUID(toState.getMembersList(), addedByRequestApprovalUuids);
|
||||
Set<DecryptedMember> addedMembers = intersectByUUID(toState.getMembersList(), subtract(newMemberUuids, addedByInvitationUuids, addedByRequestApprovalUuids));
|
||||
Set<DecryptedPendingMember> uninvitedMembers = intersectPendingByUUID(fromState.getPendingMembersList(), subtract(removedPendingMemberUuids, addedByInvitationUuids));
|
||||
Set<DecryptedPendingMember> uninvitedMembers = intersectPendingByServiceId(fromState.getPendingMembersList(), subtract(removedPendingMemberServiceIds, addedByInvitationUuids));
|
||||
Set<DecryptedRequestingMember> rejectedRequestMembers = intersectRequestingByUUID(fromState.getRequestingMembersList(), subtract(removedRequestingMemberUuids, addedByRequestApprovalUuids));
|
||||
|
||||
for (DecryptedMember member : intersectByUUID(fromState.getMembersList(), removedMemberUuids)) {
|
||||
@@ -100,18 +100,18 @@ public final class GroupChangeReconstruct {
|
||||
|
||||
for (DecryptedPendingMember uninvitedMember : uninvitedMembers) {
|
||||
builder.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(uninvitedMember.getUuid())
|
||||
.setServiceIdBinary(uninvitedMember.getServiceIdBinary())
|
||||
.setUuidCipherText(uninvitedMember.getUuidCipherText()));
|
||||
}
|
||||
|
||||
for (DecryptedPendingMember invitedMember : intersectPendingByUUID(toState.getPendingMembersList(), newPendingMemberUuids)) {
|
||||
for (DecryptedPendingMember invitedMember : intersectPendingByServiceId(toState.getPendingMembersList(), newPendingMemberServiceIds)) {
|
||||
builder.addNewPendingMembers(invitedMember);
|
||||
}
|
||||
|
||||
Set<ByteString> consistentMemberUuids = intersect(fromStateMemberUuids, toStateMemberUuids);
|
||||
Set<DecryptedMember> changedMembers = intersectByUUID(subtract(toState.getMembersList(), fromState.getMembersList()), consistentMemberUuids);
|
||||
Map<ByteString, DecryptedMember> membersUuidMap = uuidMap(fromState.getMembersList());
|
||||
Map<ByteString, DecryptedBannedMember> bannedMembersUuidMap = bannedUuidMap(toState.getBannedMembersList());
|
||||
Set<ByteString> consistentMemberUuids = intersect(fromStateMemberUuids, toStateMemberUuids);
|
||||
Set<DecryptedMember> changedMembers = intersectByUUID(subtract(toState.getMembersList(), fromState.getMembersList()), consistentMemberUuids);
|
||||
Map<ByteString, DecryptedMember> membersUuidMap = uuidMap(fromState.getMembersList());
|
||||
Map<ByteString, DecryptedBannedMember> bannedMembersServiceIdMap = bannedServiceIdMap(toState.getBannedMembersList());
|
||||
|
||||
for (DecryptedMember newState : changedMembers) {
|
||||
DecryptedMember oldState = membersUuidMap.get(newState.getUuid());
|
||||
@@ -148,13 +148,13 @@ public final class GroupChangeReconstruct {
|
||||
builder.setNewInviteLinkPassword(toState.getInviteLinkPassword());
|
||||
}
|
||||
|
||||
for (ByteString uuid : removedBannedMemberUuids) {
|
||||
builder.addDeleteBannedMembers(DecryptedBannedMember.newBuilder().setUuid(uuid).build());
|
||||
for (ByteString serviceIdBinary : removedBannedMemberServiceIds) {
|
||||
builder.addDeleteBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBinary(serviceIdBinary).build());
|
||||
}
|
||||
|
||||
for (ByteString uuid : newBannedMemberUuids) {
|
||||
DecryptedBannedMember.Builder newBannedBuilder = DecryptedBannedMember.newBuilder().setUuid(uuid);
|
||||
DecryptedBannedMember bannedMember = bannedMembersUuidMap.get(uuid);
|
||||
for (ByteString serviceIdBinary : newBannedMemberServiceIds) {
|
||||
DecryptedBannedMember.Builder newBannedBuilder = DecryptedBannedMember.newBuilder().setServiceIdBinary(serviceIdBinary);
|
||||
DecryptedBannedMember bannedMember = bannedMembersServiceIdMap.get(serviceIdBinary);
|
||||
if (bannedMember != null) {
|
||||
newBannedBuilder.setTimestamp(bannedMember.getTimestamp());
|
||||
}
|
||||
@@ -173,10 +173,10 @@ public final class GroupChangeReconstruct {
|
||||
return map;
|
||||
}
|
||||
|
||||
private static Map<ByteString, DecryptedBannedMember> bannedUuidMap(List<DecryptedBannedMember> membersList) {
|
||||
private static Map<ByteString, DecryptedBannedMember> bannedServiceIdMap(List<DecryptedBannedMember> membersList) {
|
||||
Map<ByteString, DecryptedBannedMember> map = new LinkedHashMap<>(membersList.size());
|
||||
for (DecryptedBannedMember member : membersList) {
|
||||
map.put(member.getUuid(), member);
|
||||
map.put(member.getServiceIdBinary(), member);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@@ -190,10 +190,10 @@ public final class GroupChangeReconstruct {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Set<DecryptedPendingMember> intersectPendingByUUID(Collection<DecryptedPendingMember> members, Set<ByteString> uuids) {
|
||||
private static Set<DecryptedPendingMember> intersectPendingByServiceId(Collection<DecryptedPendingMember> members, Set<ByteString> serviceIds) {
|
||||
Set<DecryptedPendingMember> result = new LinkedHashSet<>(members.size());
|
||||
for (DecryptedPendingMember member : members) {
|
||||
if (uuids.contains(member.getUuid()))
|
||||
if (serviceIds.contains(member.getServiceIdBinary()))
|
||||
result.add(member);
|
||||
}
|
||||
return result;
|
||||
@@ -208,12 +208,12 @@ public final class GroupChangeReconstruct {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Set<ByteString> pendingMembersToSetOfUuids(Collection<DecryptedPendingMember> pendingMembers) {
|
||||
Set<ByteString> uuids = new LinkedHashSet<>(pendingMembers.size());
|
||||
private static Set<ByteString> pendingMembersToSetOfServiceIds(Collection<DecryptedPendingMember> pendingMembers) {
|
||||
Set<ByteString> serviceIds = new LinkedHashSet<>(pendingMembers.size());
|
||||
for (DecryptedPendingMember pendingMember : pendingMembers) {
|
||||
uuids.add(pendingMember.getUuid());
|
||||
serviceIds.add(pendingMember.getServiceIdBinary());
|
||||
}
|
||||
return uuids;
|
||||
return serviceIds;
|
||||
}
|
||||
|
||||
private static Set<ByteString> requestingMembersToSetOfUuids(Collection<DecryptedRequestingMember> requestingMembers) {
|
||||
@@ -232,12 +232,12 @@ public final class GroupChangeReconstruct {
|
||||
return uuids;
|
||||
}
|
||||
|
||||
private static Set<ByteString> bannedMembersToSetOfUuids(Collection<DecryptedBannedMember> bannedMembers) {
|
||||
Set<ByteString> uuids = new LinkedHashSet<>(bannedMembers.size());
|
||||
private static Set<ByteString> bannedMembersToSetOfServiceIds(Collection<DecryptedBannedMember> bannedMembers) {
|
||||
Set<ByteString> serviceIds = new LinkedHashSet<>(bannedMembers.size());
|
||||
for (DecryptedBannedMember bannedMember : bannedMembers) {
|
||||
uuids.add(bannedMember.getUuid());
|
||||
serviceIds.add(bannedMember.getServiceIdBinary());
|
||||
}
|
||||
return uuids;
|
||||
return serviceIds;
|
||||
}
|
||||
|
||||
private static <T> Set<T> subtract(Collection<T> a, Collection<T> b) {
|
||||
|
||||
+28
-28
@@ -107,17 +107,17 @@ public final class GroupChangeUtil {
|
||||
DecryptedGroupChange conflictingChange,
|
||||
ChangeSetModifier changeSetModifier)
|
||||
{
|
||||
HashMap<ByteString, DecryptedMember> fullMembersByUuid = new HashMap<>(groupState.getMembersCount());
|
||||
HashMap<ByteString, DecryptedPendingMember> pendingMembersByUuid = new HashMap<>(groupState.getPendingMembersCount());
|
||||
HashMap<ByteString, DecryptedRequestingMember> requestingMembersByUuid = new HashMap<>(groupState.getMembersCount());
|
||||
HashMap<ByteString, DecryptedBannedMember> bannedMembersByUuid = new HashMap<>(groupState.getBannedMembersCount());
|
||||
HashMap<ByteString, DecryptedMember> fullMembersByUuid = new HashMap<>(groupState.getMembersCount());
|
||||
HashMap<ByteString, DecryptedPendingMember> pendingMembersByServiceId = new HashMap<>(groupState.getPendingMembersCount());
|
||||
HashMap<ByteString, DecryptedRequestingMember> requestingMembersByUuid = new HashMap<>(groupState.getMembersCount());
|
||||
HashMap<ByteString, DecryptedBannedMember> bannedMembersByServiceId = new HashMap<>(groupState.getBannedMembersCount());
|
||||
|
||||
for (DecryptedMember member : groupState.getMembersList()) {
|
||||
fullMembersByUuid.put(member.getUuid(), member);
|
||||
}
|
||||
|
||||
for (DecryptedPendingMember member : groupState.getPendingMembersList()) {
|
||||
pendingMembersByUuid.put(member.getUuid(), member);
|
||||
pendingMembersByServiceId.put(member.getServiceIdBinary(), member);
|
||||
}
|
||||
|
||||
for (DecryptedRequestingMember member : groupState.getRequestingMembersList()) {
|
||||
@@ -125,33 +125,33 @@ public final class GroupChangeUtil {
|
||||
}
|
||||
|
||||
for (DecryptedBannedMember member : groupState.getBannedMembersList()) {
|
||||
bannedMembersByUuid.put(member.getUuid(), member);
|
||||
bannedMembersByServiceId.put(member.getServiceIdBinary(), member);
|
||||
}
|
||||
|
||||
resolveField3AddMembers (conflictingChange, changeSetModifier, fullMembersByUuid, pendingMembersByUuid);
|
||||
resolveField3AddMembers (conflictingChange, changeSetModifier, fullMembersByUuid, pendingMembersByServiceId);
|
||||
resolveField4DeleteMembers (conflictingChange, changeSetModifier, fullMembersByUuid);
|
||||
resolveField5ModifyMemberRoles (conflictingChange, changeSetModifier, fullMembersByUuid);
|
||||
resolveField6ModifyProfileKeys (conflictingChange, changeSetModifier, fullMembersByUuid);
|
||||
resolveField7AddPendingMembers (conflictingChange, changeSetModifier, fullMembersByUuid, pendingMembersByUuid);
|
||||
resolveField8DeletePendingMembers (conflictingChange, changeSetModifier, pendingMembersByUuid);
|
||||
resolveField9PromotePendingMembers (conflictingChange, changeSetModifier, pendingMembersByUuid);
|
||||
resolveField7AddPendingMembers (conflictingChange, changeSetModifier, fullMembersByUuid, pendingMembersByServiceId);
|
||||
resolveField8DeletePendingMembers (conflictingChange, changeSetModifier, pendingMembersByServiceId);
|
||||
resolveField9PromotePendingMembers (conflictingChange, changeSetModifier, pendingMembersByServiceId);
|
||||
resolveField10ModifyTitle (groupState, conflictingChange, changeSetModifier);
|
||||
resolveField11ModifyAvatar (groupState, conflictingChange, changeSetModifier);
|
||||
resolveField12modifyDisappearingMessagesTimer(groupState, conflictingChange, changeSetModifier);
|
||||
resolveField13modifyAttributesAccess (groupState, conflictingChange, changeSetModifier);
|
||||
resolveField14modifyAttributesAccess (groupState, conflictingChange, changeSetModifier);
|
||||
resolveField15modifyAddFromInviteLinkAccess (groupState, conflictingChange, changeSetModifier);
|
||||
resolveField16AddRequestingMembers (conflictingChange, changeSetModifier, fullMembersByUuid, pendingMembersByUuid);
|
||||
resolveField16AddRequestingMembers (conflictingChange, changeSetModifier, fullMembersByUuid, pendingMembersByServiceId);
|
||||
resolveField17DeleteMembers (conflictingChange, changeSetModifier, requestingMembersByUuid);
|
||||
resolveField18PromoteRequestingMembers (conflictingChange, changeSetModifier, requestingMembersByUuid);
|
||||
resolveField20ModifyDescription (groupState, conflictingChange, changeSetModifier);
|
||||
resolveField21ModifyAnnouncementsOnly (groupState, conflictingChange, changeSetModifier);
|
||||
resolveField22AddBannedMembers (conflictingChange, changeSetModifier, bannedMembersByUuid);
|
||||
resolveField23DeleteBannedMembers (conflictingChange, changeSetModifier, bannedMembersByUuid);
|
||||
resolveField22AddBannedMembers (conflictingChange, changeSetModifier, bannedMembersByServiceId);
|
||||
resolveField23DeleteBannedMembers (conflictingChange, changeSetModifier, bannedMembersByServiceId);
|
||||
resolveField24PromotePendingPniAciMembers (conflictingChange, changeSetModifier, fullMembersByUuid);
|
||||
}
|
||||
|
||||
private static void resolveField3AddMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedMember> fullMembersByUuid, HashMap<ByteString, DecryptedPendingMember> pendingMembersByUuid) {
|
||||
private static void resolveField3AddMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedMember> fullMembersByUuid, HashMap<ByteString, DecryptedPendingMember> pendingMembersByServiceId) {
|
||||
List<DecryptedMember> newMembersList = conflictingChange.getNewMembersList();
|
||||
|
||||
for (int i = newMembersList.size() - 1; i >= 0; i--) {
|
||||
@@ -159,7 +159,7 @@ public final class GroupChangeUtil {
|
||||
|
||||
if (fullMembersByUuid.containsKey(member.getUuid())) {
|
||||
result.removeAddMembers(i);
|
||||
} else if (pendingMembersByUuid.containsKey(member.getUuid())) {
|
||||
} else if (pendingMembersByServiceId.containsKey(member.getUuid())) {
|
||||
result.moveAddToPromote(i);
|
||||
}
|
||||
}
|
||||
@@ -203,37 +203,37 @@ public final class GroupChangeUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveField7AddPendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedMember> fullMembersByUuid, HashMap<ByteString, DecryptedPendingMember> pendingMembersByUuid) {
|
||||
private static void resolveField7AddPendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedMember> fullMembersByUuid, HashMap<ByteString, DecryptedPendingMember> pendingMembersByServiceId) {
|
||||
List<DecryptedPendingMember> newPendingMembersList = conflictingChange.getNewPendingMembersList();
|
||||
|
||||
for (int i = newPendingMembersList.size() - 1; i >= 0; i--) {
|
||||
DecryptedPendingMember member = newPendingMembersList.get(i);
|
||||
|
||||
if (fullMembersByUuid.containsKey(member.getUuid()) || pendingMembersByUuid.containsKey(member.getUuid())) {
|
||||
if (fullMembersByUuid.containsKey(member.getServiceIdBinary()) || pendingMembersByServiceId.containsKey(member.getServiceIdBinary())) {
|
||||
result.removeAddPendingMembers(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveField8DeletePendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedPendingMember> pendingMembersByUuid) {
|
||||
private static void resolveField8DeletePendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedPendingMember> pendingMembersByServiceId) {
|
||||
List<DecryptedPendingMemberRemoval> deletePendingMembersList = conflictingChange.getDeletePendingMembersList();
|
||||
|
||||
for (int i = deletePendingMembersList.size() - 1; i >= 0; i--) {
|
||||
DecryptedPendingMemberRemoval member = deletePendingMembersList.get(i);
|
||||
|
||||
if (!pendingMembersByUuid.containsKey(member.getUuid())) {
|
||||
if (!pendingMembersByServiceId.containsKey(member.getServiceIdBinary())) {
|
||||
result.removeDeletePendingMembers(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveField9PromotePendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedPendingMember> pendingMembersByUuid) {
|
||||
private static void resolveField9PromotePendingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedPendingMember> pendingMembersByServiceId) {
|
||||
List<DecryptedMember> promotePendingMembersList = conflictingChange.getPromotePendingMembersList();
|
||||
|
||||
for (int i = promotePendingMembersList.size() - 1; i >= 0; i--) {
|
||||
DecryptedMember member = promotePendingMembersList.get(i);
|
||||
|
||||
if (!pendingMembersByUuid.containsKey(member.getUuid())) {
|
||||
if (!pendingMembersByServiceId.containsKey(member.getUuid())) {
|
||||
result.removePromotePendingMembers(i);
|
||||
}
|
||||
}
|
||||
@@ -275,7 +275,7 @@ public final class GroupChangeUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveField16AddRequestingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedMember> fullMembersByUuid, HashMap<ByteString, DecryptedPendingMember> pendingMembersByUuid) {
|
||||
private static void resolveField16AddRequestingMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedMember> fullMembersByUuid, HashMap<ByteString, DecryptedPendingMember> pendingMembersByServiceId) {
|
||||
List<DecryptedRequestingMember> newMembersList = conflictingChange.getNewRequestingMembersList();
|
||||
|
||||
for (int i = newMembersList.size() - 1; i >= 0; i--) {
|
||||
@@ -283,8 +283,8 @@ public final class GroupChangeUtil {
|
||||
|
||||
if (fullMembersByUuid.containsKey(member.getUuid())) {
|
||||
result.removeAddRequestingMembers(i);
|
||||
} else if (pendingMembersByUuid.containsKey(member.getUuid())) {
|
||||
result.moveAddRequestingMembersToPromote(i);
|
||||
} else if (pendingMembersByServiceId.containsKey(member.getUuid())) {
|
||||
result.moveAddRequestingMembersToPromote(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,25 +331,25 @@ public final class GroupChangeUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveField22AddBannedMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedBannedMember> bannedMembersByUuid) {
|
||||
private static void resolveField22AddBannedMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedBannedMember> bannedMembersByServiceId) {
|
||||
List<DecryptedBannedMember> newBannedMembersList = conflictingChange.getNewBannedMembersList();
|
||||
|
||||
for (int i = newBannedMembersList.size() - 1; i >= 0; i--) {
|
||||
DecryptedBannedMember member = newBannedMembersList.get(i);
|
||||
|
||||
if (bannedMembersByUuid.containsKey(member.getUuid())) {
|
||||
if (bannedMembersByServiceId.containsKey(member.getServiceIdBinary())) {
|
||||
result.removeAddBannedMembers(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveField23DeleteBannedMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedBannedMember> bannedMembersByUuid) {
|
||||
private static void resolveField23DeleteBannedMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedBannedMember> bannedMembersByServiceId) {
|
||||
List<DecryptedBannedMember> deleteBannedMembersList = conflictingChange.getDeleteBannedMembersList();
|
||||
|
||||
for (int i = deleteBannedMembersList.size() - 1; i >= 0; i--) {
|
||||
DecryptedBannedMember member = deleteBannedMembersList.get(i);
|
||||
|
||||
if (!bannedMembersByUuid.containsKey(member.getUuid())) {
|
||||
if (!bannedMembersByServiceId.containsKey(member.getServiceIdBinary())) {
|
||||
result.removeDeleteBannedMembers(i);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -21,7 +21,8 @@ import org.signal.storageservice.protos.groups.GroupJoinInfo;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroupJoinInfo;
|
||||
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.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.signalservice.internal.push.exceptions.ForbiddenException;
|
||||
|
||||
@@ -55,15 +56,15 @@ public class GroupsV2Api {
|
||||
/**
|
||||
* Create an auth token from a credential response.
|
||||
*/
|
||||
public GroupsV2AuthorizationString getGroupsV2AuthorizationString(ServiceId aci,
|
||||
ServiceId pni,
|
||||
public GroupsV2AuthorizationString getGroupsV2AuthorizationString(ACI aci,
|
||||
PNI pni,
|
||||
long redemptionTimeSeconds,
|
||||
GroupSecretParams groupSecretParams,
|
||||
AuthCredentialWithPniResponse authCredentialWithPniResponse)
|
||||
throws VerificationFailedException
|
||||
{
|
||||
ClientZkAuthOperations authOperations = groupsOperations.getAuthOperations();
|
||||
AuthCredentialWithPni authCredentialWithPni = authOperations.receiveAuthCredentialWithPni(aci.getRawUuid(), pni.getRawUuid(), redemptionTimeSeconds, authCredentialWithPniResponse);
|
||||
AuthCredentialWithPni authCredentialWithPni = authOperations.receiveAuthCredentialWithPniAsServiceId(aci.getLibSignalAci(), pni.getLibSignalPni(), redemptionTimeSeconds, authCredentialWithPniResponse);
|
||||
AuthCredentialPresentation authCredentialPresentation = authOperations.createAuthCredentialPresentation(new SecureRandom(), groupSecretParams, authCredentialWithPni);
|
||||
|
||||
return new GroupsV2AuthorizationString(groupSecretParams, authCredentialPresentation);
|
||||
|
||||
+114
-89
@@ -40,6 +40,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedString;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedTimer;
|
||||
import org.signal.storageservice.protos.groups.local.EnabledState;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
@@ -119,7 +120,7 @@ public final class GroupsV2Operations {
|
||||
if (expiringProfileKeyCredential != null) {
|
||||
group.addMembers(groupOperations.member(expiringProfileKeyCredential, memberRole));
|
||||
} else {
|
||||
group.addPendingMembers(groupOperations.invitee(credential.getUuid(), memberRole));
|
||||
group.addPendingMembers(groupOperations.invitee(credential.getServiceId(), memberRole));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,13 +166,13 @@ public final class GroupsV2Operations {
|
||||
return GroupChange.Actions.newBuilder().setModifyDescription(createModifyGroupDescriptionAction(description));
|
||||
}
|
||||
|
||||
public GroupChange.Actions.Builder createModifyGroupMembershipChange(Set<GroupCandidate> membersToAdd, Set<UUID> bannedMembers, UUID selfUuid) {
|
||||
public GroupChange.Actions.Builder createModifyGroupMembershipChange(Set<GroupCandidate> membersToAdd, Set<ServiceId> bannedMembers, ACI selfAci) {
|
||||
final GroupOperations groupOperations = forGroup(groupSecretParams);
|
||||
|
||||
Set<UUID> membersToUnban = membersToAdd.stream().map(GroupCandidate::getUuid).filter(bannedMembers::contains).collect(Collectors.toSet());
|
||||
Set<ServiceId> membersToUnban = membersToAdd.stream().map(GroupCandidate::getServiceId).filter(bannedMembers::contains).collect(Collectors.toSet());
|
||||
|
||||
GroupChange.Actions.Builder actions = membersToUnban.isEmpty() ? GroupChange.Actions.newBuilder()
|
||||
: createUnbanUuidsChange(membersToUnban);
|
||||
: createUnbanServiceIdsChange(membersToUnban);
|
||||
|
||||
for (GroupCandidate credential : membersToAdd) {
|
||||
Member.Role newMemberRole = Member.Role.DEFAULT;
|
||||
@@ -184,8 +185,8 @@ public final class GroupsV2Operations {
|
||||
} else {
|
||||
actions.addAddPendingMembers(GroupChange.Actions.AddPendingMemberAction
|
||||
.newBuilder()
|
||||
.setAdded(groupOperations.invitee(credential.getUuid(), newMemberRole)
|
||||
.setAddedByUserId(encryptUuid(selfUuid))));
|
||||
.setAdded(groupOperations.invitee(credential.getServiceId(), newMemberRole)
|
||||
.setAddedByUserId(encryptServiceId(selfAci))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ public final class GroupsV2Operations {
|
||||
for (UUID uuid : requestsToRemove) {
|
||||
actions.addDeleteRequestingMembers(GroupChange.Actions.DeleteRequestingMemberAction
|
||||
.newBuilder()
|
||||
.setDeletedUserId(encryptUuid(uuid)));
|
||||
.setDeletedUserId(encryptServiceId(ACI.from(uuid))));
|
||||
}
|
||||
|
||||
return actions;
|
||||
@@ -234,7 +235,7 @@ public final class GroupsV2Operations {
|
||||
actions.addPromoteRequestingMembers(GroupChange.Actions.PromoteRequestingMemberAction
|
||||
.newBuilder()
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setUserId(encryptUuid(uuid)));
|
||||
.setUserId(encryptServiceId(ACI.from(uuid))));
|
||||
}
|
||||
|
||||
return actions;
|
||||
@@ -247,7 +248,7 @@ public final class GroupsV2Operations {
|
||||
for (UUID remove: membersToRemove) {
|
||||
actions.addDeleteMembers(GroupChange.Actions.DeleteMemberAction
|
||||
.newBuilder()
|
||||
.setDeletedUserId(encryptUuid(remove)));
|
||||
.setDeletedUserId(encryptServiceId(ACI.from(remove))));
|
||||
}
|
||||
|
||||
return actions;
|
||||
@@ -259,7 +260,7 @@ public final class GroupsV2Operations {
|
||||
for (UUID member : membersToMakeAdmin) {
|
||||
actions.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction
|
||||
.newBuilder()
|
||||
.setUserId(encryptUuid(member))
|
||||
.setUserId(encryptServiceId(ACI.from(member)))
|
||||
.setRole(Member.Role.ADMINISTRATOR));
|
||||
}
|
||||
|
||||
@@ -361,6 +362,7 @@ public final class GroupsV2Operations {
|
||||
.setAnnouncementsOnly(isAnnouncementGroup));
|
||||
}
|
||||
|
||||
/** Note that this can only ban ACIs. */
|
||||
public GroupChange.Actions.Builder createBanUuidsChange(Set<UUID> banUuids, boolean rejectJoinRequest, List<DecryptedBannedMember> bannedMembersList) {
|
||||
GroupChange.Actions.Builder builder = rejectJoinRequest ? createRefuseGroupJoinRequest(banUuids, false, Collections.emptyList())
|
||||
: GroupChange.Actions.newBuilder();
|
||||
@@ -370,26 +372,26 @@ public final class GroupsV2Operations {
|
||||
List<ByteString> unban = bannedMembersList.stream()
|
||||
.sorted(Comparator.comparingLong(DecryptedBannedMember::getTimestamp))
|
||||
.limit(spacesToFree)
|
||||
.map(DecryptedBannedMember::getUuid)
|
||||
.map(DecryptedBannedMember::getServiceIdBinary)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (ByteString uuid : unban) {
|
||||
builder.addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encryptUuid(UuidUtil.fromByteString(uuid))));
|
||||
for (ByteString serviceIdBinary : unban) {
|
||||
builder.addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encryptServiceId(ServiceId.parseOrThrow(serviceIdBinary.toByteArray()))));
|
||||
}
|
||||
}
|
||||
|
||||
for (UUID uuid : banUuids) {
|
||||
builder.addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encryptUuid(uuid)).build()));
|
||||
builder.addAddBannedMembers(GroupChange.Actions.AddBannedMemberAction.newBuilder().setAdded(BannedMember.newBuilder().setUserId(encryptServiceId(ACI.from(uuid))).build()));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public GroupChange.Actions.Builder createUnbanUuidsChange(Set<UUID> banUuids) {
|
||||
public GroupChange.Actions.Builder createUnbanServiceIdsChange(Set<ServiceId> serviceIds) {
|
||||
GroupChange.Actions.Builder builder = GroupChange.Actions.newBuilder();
|
||||
|
||||
for (UUID uuid : banUuids) {
|
||||
builder.addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encryptUuid(uuid)).build());
|
||||
for (ServiceId serviceId : serviceIds) {
|
||||
builder.addDeleteBannedMembers(GroupChange.Actions.DeleteBannedMemberAction.newBuilder().setDeletedUserId(encryptServiceId(serviceId)).build());
|
||||
}
|
||||
|
||||
return builder;
|
||||
@@ -433,8 +435,8 @@ public final class GroupsV2Operations {
|
||||
.setPresentation(ByteString.copyFrom(presentation.serialize()));
|
||||
}
|
||||
|
||||
public PendingMember.Builder invitee(UUID uuid, Member.Role role) {
|
||||
UuidCiphertext uuidCiphertext = clientZkGroupCipher.encryptUuid(uuid);
|
||||
public PendingMember.Builder invitee(ServiceId serviceId, Member.Role role) {
|
||||
UuidCiphertext uuidCiphertext = clientZkGroupCipher.encrypt(serviceId.getLibSignalServiceId());
|
||||
|
||||
Member member = Member.newBuilder()
|
||||
.setRole(role)
|
||||
@@ -454,17 +456,17 @@ public final class GroupsV2Operations {
|
||||
List<DecryptedPendingMember> decryptedPendingMembers = new ArrayList<>(pendingMembersList.size());
|
||||
|
||||
for (Member member : membersList) {
|
||||
UUID memberUuid = decryptUuid(member.getUserId());
|
||||
ACI memberAci = decryptAci(member.getUserId());
|
||||
decryptedMembers.add(DecryptedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(memberUuid))
|
||||
.setUuid(memberAci.toByteString())
|
||||
.setJoinedAtRevision(member.getJoinedAtRevision())
|
||||
.build());
|
||||
}
|
||||
|
||||
for (PendingMember member : pendingMembersList) {
|
||||
UUID pendingMemberUuid = decryptUuidOrUnknown(member.getMember().getUserId());
|
||||
ServiceId pendingMemberServiceId = decryptServiceIdOrUnknown(member.getMember().getUserId());
|
||||
decryptedPendingMembers.add(DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(pendingMemberUuid))
|
||||
.setServiceIdBinary(pendingMemberServiceId.toByteString())
|
||||
.build());
|
||||
}
|
||||
|
||||
@@ -505,7 +507,7 @@ public final class GroupsV2Operations {
|
||||
}
|
||||
|
||||
for (BannedMember member : group.getBannedMembersList()) {
|
||||
decryptedBannedMembers.add(DecryptedBannedMember.newBuilder().setUuid(decryptUuidToByteString(member.getUserId())).setTimestamp(member.getTimestamp()).build());
|
||||
decryptedBannedMembers.add(DecryptedBannedMember.newBuilder().setServiceIdBinary(decryptServiceIdToBinary(member.getUserId())).setTimestamp(member.getTimestamp()).build());
|
||||
}
|
||||
|
||||
return DecryptedGroup.newBuilder()
|
||||
@@ -551,16 +553,16 @@ public final class GroupsV2Operations {
|
||||
return decryptChange(actions, null);
|
||||
}
|
||||
|
||||
public DecryptedGroupChange decryptChange(GroupChange.Actions actions, UUID source)
|
||||
public DecryptedGroupChange decryptChange(GroupChange.Actions actions, ServiceId source)
|
||||
throws VerificationFailedException, InvalidGroupStateException
|
||||
{
|
||||
DecryptedGroupChange.Builder builder = DecryptedGroupChange.newBuilder();
|
||||
|
||||
// Field 1
|
||||
if (source != null) {
|
||||
builder.setEditor(UuidUtil.toByteString(source));
|
||||
builder.setEditor(source.toByteString());
|
||||
} else {
|
||||
builder.setEditor(decryptUuidToByteString(actions.getSourceUuid()));
|
||||
builder.setEditor(decryptServiceIdToBinary(actions.getSourceUuid()));
|
||||
}
|
||||
|
||||
// Field 2
|
||||
@@ -577,35 +579,35 @@ public final class GroupsV2Operations {
|
||||
|
||||
// Field 4
|
||||
for (GroupChange.Actions.DeleteMemberAction deleteMemberAction : actions.getDeleteMembersList()) {
|
||||
builder.addDeleteMembers(decryptUuidToByteString(deleteMemberAction.getDeletedUserId()));
|
||||
builder.addDeleteMembers(decryptServiceIdToBinary(deleteMemberAction.getDeletedUserId()));
|
||||
}
|
||||
|
||||
// Field 5
|
||||
for (GroupChange.Actions.ModifyMemberRoleAction modifyMemberRoleAction : actions.getModifyMemberRolesList()) {
|
||||
builder.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder()
|
||||
.setRole(modifyMemberRoleAction.getRole())
|
||||
.setUuid(decryptUuidToByteString(modifyMemberRoleAction.getUserId())));
|
||||
.setUuid(decryptServiceIdToBinary(modifyMemberRoleAction.getUserId())));
|
||||
}
|
||||
|
||||
// Field 6
|
||||
for (GroupChange.Actions.ModifyMemberProfileKeyAction modifyMemberProfileKeyAction : actions.getModifyMemberProfileKeysList()) {
|
||||
try {
|
||||
UUID uuid;
|
||||
ACI aci;
|
||||
ProfileKey profileKey;
|
||||
|
||||
if (modifyMemberProfileKeyAction.getUserId().isEmpty() || modifyMemberProfileKeyAction.getProfileKey().isEmpty()) {
|
||||
ProfileKeyCredentialPresentation presentation = new ProfileKeyCredentialPresentation(modifyMemberProfileKeyAction.getPresentation().toByteArray());
|
||||
uuid = decryptUuid(ByteString.copyFrom(presentation.getUuidCiphertext().serialize()));
|
||||
profileKey = decryptProfileKey(ByteString.copyFrom(presentation.getProfileKeyCiphertext().serialize()), uuid);
|
||||
aci = decryptAci(ByteString.copyFrom(presentation.getUuidCiphertext().serialize()));
|
||||
profileKey = decryptProfileKey(ByteString.copyFrom(presentation.getProfileKeyCiphertext().serialize()), aci);
|
||||
} else {
|
||||
uuid = decryptUuid(modifyMemberProfileKeyAction.getUserId());
|
||||
profileKey = decryptProfileKey(modifyMemberProfileKeyAction.getProfileKey(), uuid);
|
||||
aci = decryptAci(modifyMemberProfileKeyAction.getUserId());
|
||||
profileKey = decryptProfileKey(modifyMemberProfileKeyAction.getProfileKey(), aci);
|
||||
}
|
||||
|
||||
builder.addModifiedProfileKeys(DecryptedMember.newBuilder()
|
||||
.setRole(Member.Role.UNKNOWN)
|
||||
.setJoinedAtRevision(-1)
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setUuid(aci.toByteString())
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
|
||||
} catch (InvalidInputException e) {
|
||||
throw new InvalidGroupStateException(e);
|
||||
@@ -617,45 +619,45 @@ public final class GroupsV2Operations {
|
||||
PendingMember added = addPendingMemberAction.getAdded();
|
||||
Member member = added.getMember();
|
||||
ByteString uuidCipherText = member.getUserId();
|
||||
UUID uuid = decryptUuidOrUnknown(uuidCipherText);
|
||||
ServiceId serviceId = decryptServiceIdOrUnknown(uuidCipherText);
|
||||
|
||||
builder.addNewPendingMembers(DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setServiceIdBinary(serviceId.toByteString())
|
||||
.setUuidCipherText(uuidCipherText)
|
||||
.setRole(member.getRole())
|
||||
.setAddedByUuid(decryptUuidToByteString(added.getAddedByUserId()))
|
||||
.setAddedByUuid(decryptServiceIdToBinary(added.getAddedByUserId()))
|
||||
.setTimestamp(added.getTimestamp()));
|
||||
}
|
||||
|
||||
// Field 8
|
||||
for (GroupChange.Actions.DeletePendingMemberAction deletePendingMemberAction : actions.getDeletePendingMembersList()) {
|
||||
ByteString uuidCipherText = deletePendingMemberAction.getDeletedUserId();
|
||||
UUID uuid = decryptUuidOrUnknown(uuidCipherText);
|
||||
ServiceId serviceId = decryptServiceIdOrUnknown(uuidCipherText);
|
||||
|
||||
builder.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setServiceIdBinary(serviceId.toByteString())
|
||||
.setUuidCipherText(uuidCipherText));
|
||||
}
|
||||
|
||||
// Field 9
|
||||
for (GroupChange.Actions.PromotePendingMemberAction promotePendingMemberAction : actions.getPromotePendingMembersList()) {
|
||||
try {
|
||||
UUID uuid;
|
||||
ACI aci;
|
||||
ProfileKey profileKey;
|
||||
|
||||
if (promotePendingMemberAction.getUserId().isEmpty() || promotePendingMemberAction.getProfileKey().isEmpty()) {
|
||||
ProfileKeyCredentialPresentation presentation = new ProfileKeyCredentialPresentation(promotePendingMemberAction.getPresentation().toByteArray());
|
||||
uuid = decryptUuid(ByteString.copyFrom(presentation.getUuidCiphertext().serialize()));
|
||||
profileKey = decryptProfileKey(ByteString.copyFrom(presentation.getProfileKeyCiphertext().serialize()), uuid);
|
||||
aci = decryptAci(ByteString.copyFrom(presentation.getUuidCiphertext().serialize()));
|
||||
profileKey = decryptProfileKey(ByteString.copyFrom(presentation.getProfileKeyCiphertext().serialize()), aci);
|
||||
} else {
|
||||
uuid = decryptUuid(promotePendingMemberAction.getUserId());
|
||||
profileKey = decryptProfileKey(promotePendingMemberAction.getProfileKey(), uuid);
|
||||
aci = decryptAci(promotePendingMemberAction.getUserId());
|
||||
profileKey = decryptProfileKey(promotePendingMemberAction.getProfileKey(), aci);
|
||||
}
|
||||
|
||||
builder.addPromotePendingMembers(DecryptedMember.newBuilder()
|
||||
.setJoinedAtRevision(-1)
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setUuid(aci.toByteString())
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize())));
|
||||
} catch (InvalidInputException e) {
|
||||
throw new InvalidGroupStateException(e);
|
||||
@@ -700,12 +702,12 @@ public final class GroupsV2Operations {
|
||||
|
||||
// Field 17
|
||||
for (GroupChange.Actions.DeleteRequestingMemberAction delete : actions.getDeleteRequestingMembersList()) {
|
||||
builder.addDeleteRequestingMembers(decryptUuidToByteString(delete.getDeletedUserId()));
|
||||
builder.addDeleteRequestingMembers(decryptServiceIdToBinary(delete.getDeletedUserId()));
|
||||
}
|
||||
|
||||
// Field 18
|
||||
for (GroupChange.Actions.PromoteRequestingMemberAction promote : actions.getPromoteRequestingMembersList()) {
|
||||
builder.addPromoteRequestingMembers(DecryptedApproveMember.newBuilder().setRole(promote.getRole()).setUuid(decryptUuidToByteString(promote.getUserId())));
|
||||
builder.addPromoteRequestingMembers(DecryptedApproveMember.newBuilder().setRole(promote.getRole()).setUuid(decryptServiceIdToBinary(promote.getUserId())));
|
||||
}
|
||||
|
||||
// Field 19
|
||||
@@ -725,27 +727,31 @@ public final class GroupsV2Operations {
|
||||
|
||||
// Field 22
|
||||
for (GroupChange.Actions.AddBannedMemberAction action : actions.getAddBannedMembersList()) {
|
||||
builder.addNewBannedMembers(DecryptedBannedMember.newBuilder().setUuid(decryptUuidToByteString(action.getAdded().getUserId())).setTimestamp(action.getAdded().getTimestamp()).build());
|
||||
builder.addNewBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBinary(decryptServiceIdToBinary(action.getAdded().getUserId())).setTimestamp(action.getAdded().getTimestamp()).build());
|
||||
}
|
||||
|
||||
// Field 23
|
||||
for (GroupChange.Actions.DeleteBannedMemberAction action : actions.getDeleteBannedMembersList()) {
|
||||
builder.addDeleteBannedMembers(DecryptedBannedMember.newBuilder().setUuid(decryptUuidToByteString(action.getDeletedUserId())).build());
|
||||
builder.addDeleteBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBinary(decryptServiceIdToBinary(action.getDeletedUserId())).build());
|
||||
}
|
||||
|
||||
// Field 24
|
||||
for (GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction promotePendingPniAciMemberAction : actions.getPromotePendingPniAciMembersList()) {
|
||||
UUID uuid = decryptUuid(promotePendingPniAciMemberAction.getUserId());
|
||||
UUID pni = decryptUuid(promotePendingPniAciMemberAction.getPni());
|
||||
ProfileKey profileKey = decryptProfileKey(promotePendingPniAciMemberAction.getProfileKey(), uuid);
|
||||
ACI aci = decryptAci(promotePendingPniAciMemberAction.getUserId());
|
||||
ServiceId pni = decryptServiceId(promotePendingPniAciMemberAction.getPni());
|
||||
ProfileKey profileKey = decryptProfileKey(promotePendingPniAciMemberAction.getProfileKey(), aci);
|
||||
|
||||
builder.setEditor(UuidUtil.toByteString(uuid))
|
||||
if (!(pni instanceof PNI)) {
|
||||
throw new InvalidGroupStateException();
|
||||
}
|
||||
|
||||
builder.setEditor(aci.toByteString())
|
||||
.addPromotePendingPniAciMembers(DecryptedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setUuid(aci.toByteString())
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setJoinedAtRevision(actions.getRevision())
|
||||
.setPni(UuidUtil.toByteString(pni)));
|
||||
.setPni(pni.toByteString()));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
@@ -767,20 +773,26 @@ public final class GroupsV2Operations {
|
||||
throws InvalidGroupStateException, VerificationFailedException, InvalidInputException
|
||||
{
|
||||
if (member.getPresentation().isEmpty()) {
|
||||
UUID uuid = decryptUuid(member.getUserId());
|
||||
ACI aci = decryptAci(member.getUserId());
|
||||
|
||||
return DecryptedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setUuid(aci.toByteString())
|
||||
.setJoinedAtRevision(member.getJoinedAtRevision())
|
||||
.setProfileKey(decryptProfileKeyToByteString(member.getProfileKey(), uuid))
|
||||
.setProfileKey(decryptProfileKeyToByteString(member.getProfileKey(), aci))
|
||||
.setRole(member.getRole());
|
||||
} else {
|
||||
ProfileKeyCredentialPresentation profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(member.getPresentation().toByteArray());
|
||||
UUID uuid = clientZkGroupCipher.decryptUuid(profileKeyCredentialPresentation.getUuidCiphertext());
|
||||
ProfileKey profileKey = clientZkGroupCipher.decryptProfileKey(profileKeyCredentialPresentation.getProfileKeyCiphertext(), uuid);
|
||||
|
||||
ServiceId serviceId = ServiceId.fromLibSignal(clientZkGroupCipher.decrypt(profileKeyCredentialPresentation.getUuidCiphertext()));
|
||||
if (!(serviceId instanceof ACI)) {
|
||||
throw new InvalidGroupStateException();
|
||||
}
|
||||
ACI serviceIdAsAci = (ACI)serviceId;
|
||||
|
||||
ProfileKey profileKey = clientZkGroupCipher.decryptProfileKey(profileKeyCredentialPresentation.getProfileKeyCiphertext(), serviceIdAsAci.getLibSignalAci());
|
||||
|
||||
return DecryptedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setUuid(serviceIdAsAci.toByteString())
|
||||
.setJoinedAtRevision(member.getJoinedAtRevision())
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setRole(member.getRole());
|
||||
@@ -791,8 +803,8 @@ public final class GroupsV2Operations {
|
||||
throws InvalidGroupStateException, VerificationFailedException
|
||||
{
|
||||
ByteString userIdCipherText = member.getMember().getUserId();
|
||||
UUID uuid = decryptUuidOrUnknown(userIdCipherText);
|
||||
UUID addedBy = decryptUuid(member.getAddedByUserId());
|
||||
ServiceId serviceId = decryptServiceIdOrUnknown(userIdCipherText);
|
||||
ACI addedBy = decryptAci(member.getAddedByUserId());
|
||||
|
||||
Member.Role role = member.getMember().getRole();
|
||||
|
||||
@@ -801,9 +813,9 @@ public final class GroupsV2Operations {
|
||||
}
|
||||
|
||||
return DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setServiceIdBinary(serviceId.toByteString())
|
||||
.setUuidCipherText(userIdCipherText)
|
||||
.setAddedByUuid(UuidUtil.toByteString(addedBy))
|
||||
.setAddedByUuid(addedBy.toByteString())
|
||||
.setRole(role)
|
||||
.setTimestamp(member.getTimestamp())
|
||||
.build();
|
||||
@@ -813,11 +825,11 @@ public final class GroupsV2Operations {
|
||||
throws InvalidGroupStateException, VerificationFailedException
|
||||
{
|
||||
if (member.getPresentation().isEmpty()) {
|
||||
UUID uuid = decryptUuid(member.getUserId());
|
||||
ACI aci = decryptAci(member.getUserId());
|
||||
|
||||
return DecryptedRequestingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setProfileKey(decryptProfileKeyToByteString(member.getProfileKey(), uuid))
|
||||
.setUuid(aci.toByteString())
|
||||
.setProfileKey(decryptProfileKeyToByteString(member.getProfileKey(), aci))
|
||||
.setTimestamp(member.getTimestamp())
|
||||
.build();
|
||||
} else {
|
||||
@@ -828,54 +840,67 @@ public final class GroupsV2Operations {
|
||||
throw new InvalidGroupStateException(e);
|
||||
}
|
||||
|
||||
UUID uuid = clientZkGroupCipher.decryptUuid(profileKeyCredentialPresentation.getUuidCiphertext());
|
||||
ProfileKey profileKey = clientZkGroupCipher.decryptProfileKey(profileKeyCredentialPresentation.getProfileKeyCiphertext(), uuid);
|
||||
ServiceId serviceId = ServiceId.fromLibSignal(clientZkGroupCipher.decrypt(profileKeyCredentialPresentation.getUuidCiphertext()));
|
||||
if (!(serviceId instanceof ACI)) {
|
||||
throw new InvalidGroupStateException();
|
||||
}
|
||||
ACI serviceIdAsAci = (ACI)serviceId;
|
||||
|
||||
ProfileKey profileKey = clientZkGroupCipher.decryptProfileKey(profileKeyCredentialPresentation.getProfileKeyCiphertext(), serviceIdAsAci.getLibSignalAci());
|
||||
|
||||
return DecryptedRequestingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setUuid(serviceIdAsAci.toByteString())
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private ProfileKey decryptProfileKey(ByteString profileKey, UUID uuid) throws VerificationFailedException, InvalidGroupStateException {
|
||||
private ProfileKey decryptProfileKey(ByteString profileKey, ACI aci) throws VerificationFailedException, InvalidGroupStateException {
|
||||
try {
|
||||
ProfileKeyCiphertext profileKeyCiphertext = new ProfileKeyCiphertext(profileKey.toByteArray());
|
||||
return clientZkGroupCipher.decryptProfileKey(profileKeyCiphertext, uuid);
|
||||
return clientZkGroupCipher.decryptProfileKey(profileKeyCiphertext, aci.getLibSignalAci());
|
||||
} catch (InvalidInputException e) {
|
||||
throw new InvalidGroupStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private ByteString decryptProfileKeyToByteString(ByteString profileKey, UUID uuid) throws VerificationFailedException, InvalidGroupStateException {
|
||||
return ByteString.copyFrom(decryptProfileKey(profileKey, uuid).serialize());
|
||||
private ByteString decryptProfileKeyToByteString(ByteString profileKey, ACI aci) throws VerificationFailedException, InvalidGroupStateException {
|
||||
return ByteString.copyFrom(decryptProfileKey(profileKey, aci).serialize());
|
||||
}
|
||||
|
||||
private ByteString decryptUuidToByteString(ByteString userId) throws InvalidGroupStateException, VerificationFailedException {
|
||||
return UuidUtil.toByteString(decryptUuid(userId));
|
||||
private ByteString decryptServiceIdToBinary(ByteString userId) throws InvalidGroupStateException, VerificationFailedException {
|
||||
return decryptServiceId(userId).toByteString();
|
||||
}
|
||||
|
||||
// Visible for Testing
|
||||
public ByteString encryptUuid(UUID uuid) {
|
||||
return ByteString.copyFrom(clientZkGroupCipher.encryptUuid(uuid).serialize());
|
||||
public ByteString encryptServiceId(ServiceId serviceId) {
|
||||
return ByteString.copyFrom(clientZkGroupCipher.encrypt(serviceId.getLibSignalServiceId()).serialize());
|
||||
}
|
||||
|
||||
private UUID decryptUuid(ByteString userId) throws InvalidGroupStateException, VerificationFailedException {
|
||||
private ServiceId decryptServiceId(ByteString userId) throws InvalidGroupStateException, VerificationFailedException {
|
||||
try {
|
||||
return clientZkGroupCipher.decryptUuid(new UuidCiphertext(userId.toByteArray()));
|
||||
return ServiceId.fromLibSignal(clientZkGroupCipher.decrypt(new UuidCiphertext(userId.toByteArray())));
|
||||
} catch (InvalidInputException e) {
|
||||
throw new InvalidGroupStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private ACI decryptAci(ByteString userId) throws InvalidGroupStateException, VerificationFailedException {
|
||||
ServiceId result = decryptServiceId(userId);
|
||||
if (result instanceof ACI) {
|
||||
return (ACI)result;
|
||||
}
|
||||
throw new InvalidGroupStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to decrypt a UUID, but will return {@link #UNKNOWN_UUID} if it cannot.
|
||||
* Attempts to decrypt a UUID, but will return an ACI of {@link #UNKNOWN_UUID} if it cannot.
|
||||
*/
|
||||
private UUID decryptUuidOrUnknown(ByteString userId) {
|
||||
private ServiceId decryptServiceIdOrUnknown(ByteString userId) {
|
||||
try {
|
||||
return clientZkGroupCipher.decryptUuid(new UuidCiphertext(userId.toByteArray()));
|
||||
return ServiceId.fromLibSignal(clientZkGroupCipher.decrypt(new UuidCiphertext(userId.toByteArray())));
|
||||
} catch (InvalidInputException | VerificationFailedException e) {
|
||||
return UNKNOWN_UUID;
|
||||
return ACI.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,10 +1002,10 @@ public final class GroupsV2Operations {
|
||||
return GroupChange.Actions.parseFrom(groupChange.getActions());
|
||||
}
|
||||
|
||||
public GroupChange.Actions.Builder createChangeMemberRole(UUID uuid, Member.Role role) {
|
||||
public GroupChange.Actions.Builder createChangeMemberRole(ACI memberAci, Member.Role role) {
|
||||
return GroupChange.Actions.newBuilder()
|
||||
.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder()
|
||||
.setUserId(encryptUuid(uuid))
|
||||
.setUserId(encryptServiceId(memberAci))
|
||||
.setRole(role));
|
||||
}
|
||||
|
||||
@@ -990,7 +1015,7 @@ public final class GroupsV2Operations {
|
||||
GroupChange.Actions.AddMemberAction addMember = addMembers.get(i);
|
||||
ProfileKeyCredentialPresentation profileKeyCredentialPresentation = new ProfileKeyCredentialPresentation(addMember.getAdded().getPresentation().toByteArray());
|
||||
|
||||
ids.add(ACI.from(clientZkGroupCipher.decryptUuid(profileKeyCredentialPresentation.getUuidCiphertext())));
|
||||
ids.add(ServiceId.fromLibSignal(clientZkGroupCipher.decrypt(profileKeyCredentialPresentation.getUuidCiphertext())));
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
+24
-19
@@ -19,8 +19,17 @@ import org.signal.libsignal.protocol.ServiceId.Pni as LibSignalPni
|
||||
* The only times you truly know, and the only times you should actually care, is during CDS refreshes or specific inbound messages
|
||||
* that link them together.
|
||||
*/
|
||||
sealed class ServiceId(@JvmField protected val libsignalServiceId: LibSignalServiceId) {
|
||||
sealed class ServiceId(val libSignalServiceId: LibSignalServiceId) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromLibSignal(serviceId: LibSignalServiceId): ServiceId {
|
||||
return when (serviceId) {
|
||||
is LibSignalAci -> ACI(serviceId)
|
||||
is LibSignalPni -> PNI(serviceId)
|
||||
else -> throw IllegalArgumentException("Unknown libsignal ServiceId type!")
|
||||
}
|
||||
}
|
||||
|
||||
/** Parses a ServiceId serialized as a string. Returns null if the ServiceId is invalid. */
|
||||
@JvmStatic
|
||||
fun parseOrNull(raw: String?): ServiceId? {
|
||||
@@ -29,11 +38,7 @@ sealed class ServiceId(@JvmField protected val libsignalServiceId: LibSignalServ
|
||||
}
|
||||
|
||||
return try {
|
||||
when (val serviceId = LibSignalServiceId.parseFromString(raw)) {
|
||||
is LibSignalAci -> ACI(serviceId)
|
||||
is LibSignalPni -> PNI(serviceId)
|
||||
else -> null
|
||||
}
|
||||
fromLibSignal(LibSignalServiceId.parseFromString(raw))
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
} catch (e: InvalidServiceIdException) {
|
||||
@@ -49,11 +54,7 @@ sealed class ServiceId(@JvmField protected val libsignalServiceId: LibSignalServ
|
||||
}
|
||||
|
||||
return try {
|
||||
return when (val serviceId = LibSignalServiceId.parseFromBinary(raw)) {
|
||||
is LibSignalAci -> ACI.from(serviceId.rawUUID)
|
||||
is LibSignalPni -> PNI.from(serviceId.rawUUID)
|
||||
else -> null
|
||||
}
|
||||
fromLibSignal(LibSignalServiceId.parseFromBinary(raw))
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
} catch (e: InvalidServiceIdException) {
|
||||
@@ -61,6 +62,10 @@ sealed class ServiceId(@JvmField protected val libsignalServiceId: LibSignalServ
|
||||
}
|
||||
}
|
||||
|
||||
/** Parses a ServiceId serialized as a ByteString. Returns null if the ServiceId is invalid. */
|
||||
@JvmStatic
|
||||
fun parseOrNull(bytes: ByteString): ServiceId? = parseOrNull(bytes.toByteArray())
|
||||
|
||||
/** Parses a ServiceId serialized as a string. Crashes if the ServiceId is invalid. */
|
||||
@JvmStatic
|
||||
@Throws(IllegalArgumentException::class)
|
||||
@@ -77,27 +82,27 @@ sealed class ServiceId(@JvmField protected val libsignalServiceId: LibSignalServ
|
||||
fun parseOrThrow(bytes: ByteString): ServiceId = parseOrThrow(bytes.toByteArray())
|
||||
}
|
||||
|
||||
val rawUuid: UUID = libsignalServiceId.rawUUID
|
||||
val rawUuid: UUID = libSignalServiceId.rawUUID
|
||||
|
||||
val isUnknown: Boolean = rawUuid == UuidUtil.UNKNOWN_UUID
|
||||
|
||||
val isValid: Boolean = !isUnknown
|
||||
|
||||
fun toProtocolAddress(deviceId: Int): SignalProtocolAddress = SignalProtocolAddress(libsignalServiceId.toServiceIdString(), deviceId)
|
||||
fun toProtocolAddress(deviceId: Int): SignalProtocolAddress = SignalProtocolAddress(libSignalServiceId.toServiceIdString(), deviceId)
|
||||
|
||||
fun toByteString(): ByteString = ByteString.copyFrom(libsignalServiceId.toServiceIdBinary())
|
||||
fun toByteString(): ByteString = ByteString.copyFrom(libSignalServiceId.toServiceIdBinary())
|
||||
|
||||
fun toByteArray(): ByteArray = libsignalServiceId.toServiceIdBinary()
|
||||
fun toByteArray(): ByteArray = libSignalServiceId.toServiceIdBinary()
|
||||
|
||||
fun logString(): String = libsignalServiceId.toLogString()
|
||||
fun logString(): String = libSignalServiceId.toLogString()
|
||||
|
||||
/**
|
||||
* A serialized string that can be parsed via [parseOrThrow], for instance.
|
||||
* Basically ACI's are just normal UUIDs, and PNI's are UUIDs with a `PNI:` prefix.
|
||||
*/
|
||||
override fun toString(): String = libsignalServiceId.toServiceIdString()
|
||||
override fun toString(): String = libSignalServiceId.toServiceIdString()
|
||||
|
||||
data class ACI(val libsignalAci: LibSignalAci) : ServiceId(libsignalAci) {
|
||||
data class ACI(val libSignalAci: LibSignalAci) : ServiceId(libSignalAci) {
|
||||
companion object {
|
||||
@JvmField
|
||||
val UNKNOWN = from(UuidUtil.UNKNOWN_UUID)
|
||||
@@ -133,7 +138,7 @@ sealed class ServiceId(@JvmField protected val libsignalServiceId: LibSignalServ
|
||||
override fun toString(): String = super.toString()
|
||||
}
|
||||
|
||||
data class PNI(private val libsignalPni: LibSignalPni) : ServiceId(libsignalPni) {
|
||||
data class PNI(val libSignalPni: LibSignalPni) : ServiceId(libSignalPni) {
|
||||
companion object {
|
||||
@JvmField
|
||||
var UNKNOWN = from(UuidUtil.UNKNOWN_UUID)
|
||||
|
||||
+10
-2
@@ -1,6 +1,7 @@
|
||||
package org.whispersystems.signalservice.api.services;
|
||||
|
||||
import org.signal.libsignal.protocol.IdentityKey;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.signal.libsignal.protocol.util.Pair;
|
||||
import org.signal.libsignal.zkgroup.VerificationFailedException;
|
||||
import org.signal.libsignal.zkgroup.profiles.ClientZkProfileOperations;
|
||||
@@ -15,6 +16,7 @@ import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
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.push.exceptions.MalformedResponseException;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
@@ -81,11 +83,17 @@ public final class ProfileService {
|
||||
.setVerb("GET");
|
||||
|
||||
if (profileKey.isPresent()) {
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.get().getProfileKeyVersion(serviceId.getRawUuid());
|
||||
if (!(serviceId instanceof ACI)) {
|
||||
Log.w(TAG, "ServiceId must be an ACI if a profile key is available!");
|
||||
return Single.just(ServiceResponse.forUnknownError(new IllegalArgumentException("ServiceId must be an ACI if a profile key is available!")));
|
||||
}
|
||||
|
||||
ACI aci = (ACI) serviceId;
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.get().getProfileKeyVersion(aci.getLibSignalAci());
|
||||
String version = profileKeyIdentifier.serialize();
|
||||
|
||||
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
|
||||
requestContext = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, serviceId.getRawUuid(), profileKey.get());
|
||||
requestContext = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, aci.getLibSignalAci(), profileKey.get());
|
||||
|
||||
ProfileKeyCredentialRequest request = requestContext.getRequest();
|
||||
String credentialRequest = Hex.toStringCondensed(request.serialize());
|
||||
|
||||
+6
-6
@@ -258,7 +258,7 @@ public class PushServiceSocket {
|
||||
private static final String STICKER_MANIFEST_PATH = "stickers/%s/manifest.proto";
|
||||
private static final String STICKER_PATH = "stickers/%s/full/%d";
|
||||
|
||||
private static final String GROUPSV2_CREDENTIAL = "/v1/certificate/auth/group?redemptionStartSeconds=%d&redemptionEndSeconds=%d";
|
||||
private static final String GROUPSV2_CREDENTIAL = "/v1/certificate/auth/group?redemptionStartSeconds=%d&redemptionEndSeconds=%d&pniAsServiceId=true";
|
||||
private static final String GROUPSV2_GROUP = "/v1/groups/";
|
||||
private static final String GROUPSV2_GROUP_PASSWORD = "/v1/groups/?inviteLinkPassword=%s";
|
||||
private static final String GROUPSV2_GROUP_CHANGES = "/v1/groups/logs/%s?maxSupportedChangeEpoch=%d&includeFirstState=%s&includeLastState=false";
|
||||
@@ -853,9 +853,9 @@ public class PushServiceSocket {
|
||||
});
|
||||
}
|
||||
|
||||
public ListenableFuture<ProfileAndCredential> retrieveVersionedProfileAndCredential(UUID target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess, Locale locale) {
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.getProfileKeyVersion(target);
|
||||
ProfileKeyCredentialRequestContext requestContext = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, target, profileKey);
|
||||
public ListenableFuture<ProfileAndCredential> retrieveVersionedProfileAndCredential(ACI target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess, Locale locale) {
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.getProfileKeyVersion(target.getLibSignalAci());
|
||||
ProfileKeyCredentialRequestContext requestContext = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, target.getLibSignalAci(), profileKey);
|
||||
ProfileKeyCredentialRequest request = requestContext.getRequest();
|
||||
|
||||
String version = profileKeyIdentifier.serialize();
|
||||
@@ -889,8 +889,8 @@ public class PushServiceSocket {
|
||||
}
|
||||
}
|
||||
|
||||
public ListenableFuture<SignalServiceProfile> retrieveVersionedProfile(UUID target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess, Locale locale) {
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.getProfileKeyVersion(target);
|
||||
public ListenableFuture<SignalServiceProfile> retrieveVersionedProfile(ACI target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess, Locale locale) {
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.getProfileKeyVersion(target.getLibSignalAci());
|
||||
|
||||
String version = profileKeyIdentifier.serialize();
|
||||
String subPath = String.format("%s/%s", target, version);
|
||||
|
||||
@@ -21,11 +21,11 @@ message DecryptedMember {
|
||||
}
|
||||
|
||||
message DecryptedPendingMember {
|
||||
bytes uuid = 1;
|
||||
Member.Role role = 2;
|
||||
bytes addedByUuid = 3;
|
||||
uint64 timestamp = 4;
|
||||
bytes uuidCipherText = 5;
|
||||
bytes serviceIdBinary = 1;
|
||||
Member.Role role = 2;
|
||||
bytes addedByUuid = 3;
|
||||
uint64 timestamp = 4;
|
||||
bytes uuidCipherText = 5;
|
||||
}
|
||||
|
||||
message DecryptedRequestingMember {
|
||||
@@ -35,13 +35,13 @@ message DecryptedRequestingMember {
|
||||
}
|
||||
|
||||
message DecryptedBannedMember {
|
||||
bytes uuid = 1;
|
||||
uint64 timestamp = 2;
|
||||
bytes serviceIdBinary = 1;
|
||||
uint64 timestamp = 2;
|
||||
}
|
||||
|
||||
message DecryptedPendingMemberRemoval {
|
||||
bytes uuid = 1;
|
||||
bytes uuidCipherText = 2;
|
||||
bytes serviceIdBinary = 1;
|
||||
bytes uuidCipherText = 2;
|
||||
}
|
||||
|
||||
message DecryptedApproveMember {
|
||||
|
||||
+31
-28
@@ -7,6 +7,8 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemoval;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
|
||||
@@ -15,6 +17,7 @@ import java.util.UUID;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
@@ -58,39 +61,39 @@ public final class DecryptedGroupUtilTest {
|
||||
|
||||
@Test
|
||||
public void can_extract_uuid_from_decrypted_pending_member() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
ACI aci = ACI.from(UUID.randomUUID());
|
||||
DecryptedPendingMember decryptedMember = DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setServiceIdBinary(aci.toByteString())
|
||||
.build();
|
||||
|
||||
UUID parsed = DecryptedGroupUtil.toUuid(decryptedMember);
|
||||
ServiceId parsed = ServiceId.parseOrNull(decryptedMember.getServiceIdBinary());
|
||||
|
||||
assertEquals(uuid, parsed);
|
||||
assertEquals(aci, parsed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_extract_uuid_from_bad_decrypted_pending_member() {
|
||||
DecryptedPendingMember decryptedMember = DecryptedPendingMember.newBuilder()
|
||||
.setUuid(ByteString.copyFrom(Util.getSecretBytes(17)))
|
||||
.setServiceIdBinary(ByteString.copyFrom(Util.getSecretBytes(18)))
|
||||
.build();
|
||||
|
||||
UUID parsed = DecryptedGroupUtil.toUuid(decryptedMember);
|
||||
ServiceId parsed = ServiceId.parseOrNull(decryptedMember.getServiceIdBinary());
|
||||
|
||||
assertEquals(UuidUtil.UNKNOWN_UUID, parsed);
|
||||
assertNull(parsed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_extract_uuids_for_all_pending_including_bad_entries() {
|
||||
UUID uuid1 = UUID.randomUUID();
|
||||
UUID uuid2 = UUID.randomUUID();
|
||||
ACI aci1 = ACI.from(UUID.randomUUID());
|
||||
ACI aci2 = ACI.from(UUID.randomUUID());
|
||||
DecryptedPendingMember decryptedMember1 = DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid1))
|
||||
.setServiceIdBinary(aci1.toByteString())
|
||||
.build();
|
||||
DecryptedPendingMember decryptedMember2 = DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid2))
|
||||
.setServiceIdBinary(aci2.toByteString())
|
||||
.build();
|
||||
DecryptedPendingMember decryptedMember3 = DecryptedPendingMember.newBuilder()
|
||||
.setUuid(ByteString.copyFrom(Util.getSecretBytes(17)))
|
||||
.setServiceIdBinary(ByteString.copyFrom(Util.getSecretBytes(18)))
|
||||
.build();
|
||||
|
||||
DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder()
|
||||
@@ -99,23 +102,23 @@ public final class DecryptedGroupUtilTest {
|
||||
.addNewPendingMembers(decryptedMember3)
|
||||
.build();
|
||||
|
||||
List<UUID> pendingUuids = DecryptedGroupUtil.pendingToUuidList(groupChange.getNewPendingMembersList());
|
||||
List<ServiceId> pendingUuids = DecryptedGroupUtil.pendingToServiceIdList(groupChange.getNewPendingMembersList());
|
||||
|
||||
assertThat(pendingUuids, is(asList(uuid1, uuid2, UuidUtil.UNKNOWN_UUID)));
|
||||
assertThat(pendingUuids, is(asList(aci1, aci2, ACI.UNKNOWN)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_extract_uuids_for_all_deleted_pending_excluding_bad_entries() {
|
||||
UUID uuid1 = UUID.randomUUID();
|
||||
UUID uuid2 = UUID.randomUUID();
|
||||
ACI aci1 = ACI.from(UUID.randomUUID());
|
||||
ACI aci2 = ACI.from(UUID.randomUUID());
|
||||
DecryptedPendingMemberRemoval decryptedMember1 = DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid1))
|
||||
.setServiceIdBinary(aci1.toByteString())
|
||||
.build();
|
||||
DecryptedPendingMemberRemoval decryptedMember2 = DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid2))
|
||||
.setServiceIdBinary(aci2.toByteString())
|
||||
.build();
|
||||
DecryptedPendingMemberRemoval decryptedMember3 = DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(ByteString.copyFrom(Util.getSecretBytes(17)))
|
||||
.setServiceIdBinary(ByteString.copyFrom(Util.getSecretBytes(18)))
|
||||
.build();
|
||||
|
||||
DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder()
|
||||
@@ -124,23 +127,23 @@ public final class DecryptedGroupUtilTest {
|
||||
.addDeletePendingMembers(decryptedMember3)
|
||||
.build();
|
||||
|
||||
List<UUID> removedUuids = DecryptedGroupUtil.removedPendingMembersUuidList(groupChange);
|
||||
List<ServiceId> removedUuids = DecryptedGroupUtil.removedPendingMembersServiceIdList(groupChange);
|
||||
|
||||
assertThat(removedUuids, is(asList(uuid1, uuid2)));
|
||||
assertThat(removedUuids, is(asList(aci1, aci2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_extract_uuids_for_all_deleted_members_excluding_bad_entries() {
|
||||
UUID uuid1 = UUID.randomUUID();
|
||||
UUID uuid2 = UUID.randomUUID();
|
||||
ACI aci1 = ACI.from(UUID.randomUUID());
|
||||
ACI aci2 = ACI.from(UUID.randomUUID());
|
||||
DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder()
|
||||
.addDeleteMembers(UuidUtil.toByteString(uuid1))
|
||||
.addDeleteMembers(UuidUtil.toByteString(uuid2))
|
||||
.addDeleteMembers(ByteString.copyFrom(Util.getSecretBytes(17)))
|
||||
.addDeleteMembers(aci1.toByteString())
|
||||
.addDeleteMembers(aci2.toByteString())
|
||||
.addDeleteMembers(ByteString.copyFrom(Util.getSecretBytes(18)))
|
||||
.build();
|
||||
|
||||
List<UUID> removedUuids = DecryptedGroupUtil.removedMembersUuidList(groupChange);
|
||||
List<ServiceId> removedServiceIds = DecryptedGroupUtil.removedMembersServiceIdList(groupChange);
|
||||
|
||||
assertThat(removedUuids, is(asList(uuid1, uuid2)));
|
||||
assertThat(removedServiceIds, is(asList(aci1, aci2)));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -949,7 +949,7 @@ public final class DecryptedGroupUtil_apply_Test {
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.setRevision(11)
|
||||
.addDeleteBannedMembers(DecryptedBannedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(bannedUuid))
|
||||
.setServiceIdBinary(UuidUtil.toByteString(bannedUuid))
|
||||
.build())
|
||||
.build());
|
||||
|
||||
|
||||
+10
-7
@@ -12,6 +12,8 @@ import org.signal.storageservice.protos.groups.GroupChange;
|
||||
import org.signal.storageservice.protos.groups.GroupChange.Actions.AddBannedMemberAction;
|
||||
import org.signal.storageservice.protos.groups.GroupChange.Actions.DeleteBannedMemberAction;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedBannedMember;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
import org.whispersystems.signalservice.testutil.LibSignalLibraryUtil;
|
||||
@@ -52,7 +54,7 @@ public final class GroupsV2Operations_ban_Test {
|
||||
Collections.emptyList());
|
||||
|
||||
assertThat(banUuidsChange.getAddBannedMembersCount(), is(1));
|
||||
assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptUuid(ban)));
|
||||
assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptServiceId(ACI.from(ban))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -69,7 +71,7 @@ public final class GroupsV2Operations_ban_Test {
|
||||
alreadyBanned);
|
||||
|
||||
assertThat(banUuidsChange.getAddBannedMembersCount(), is(1));
|
||||
assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptUuid(toBan)));
|
||||
assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptServiceId(ACI.from(toBan))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,11 +95,11 @@ public final class GroupsV2Operations_ban_Test {
|
||||
alreadyBanned);
|
||||
|
||||
assertThat(banUuidsChange.getDeleteBannedMembersCount(), is(1));
|
||||
assertThat(banUuidsChange.getDeleteBannedMembers(0).getDeletedUserId(), is(groupOperations.encryptUuid(UuidUtil.fromByteString(oldest.getUuid()))));
|
||||
assertThat(banUuidsChange.getDeleteBannedMembers(0).getDeletedUserId(), is(groupOperations.encryptServiceId(ServiceId.parseOrThrow(oldest.getServiceIdBinary()))));
|
||||
|
||||
|
||||
assertThat(banUuidsChange.getAddBannedMembersCount(), is(1));
|
||||
assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptUuid(toBan)));
|
||||
assertThat(banUuidsChange.getAddBannedMembers(0).getAdded().getUserId(), is(groupOperations.encryptServiceId(ACI.from(toBan))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,8 +114,8 @@ public final class GroupsV2Operations_ban_Test {
|
||||
}
|
||||
|
||||
List<ByteString> oldest = new ArrayList<>(2);
|
||||
oldest.add(groupOperations.encryptUuid(UuidUtil.fromByteString(alreadyBanned.get(0).getUuid())));
|
||||
oldest.add(groupOperations.encryptUuid(UuidUtil.fromByteString(alreadyBanned.get(1).getUuid())));
|
||||
oldest.add(groupOperations.encryptServiceId(ServiceId.parseOrThrow(alreadyBanned.get(0).getServiceIdBinary())));
|
||||
oldest.add(groupOperations.encryptServiceId(ServiceId.parseOrThrow(alreadyBanned.get(1).getServiceIdBinary())));
|
||||
|
||||
Collections.shuffle(alreadyBanned);
|
||||
|
||||
@@ -135,6 +137,7 @@ public final class GroupsV2Operations_ban_Test {
|
||||
.map(AddBannedMemberAction::getAdded)
|
||||
.map(BannedMember::getUserId)
|
||||
.collect(Collectors.toList()),
|
||||
hasItems(groupOperations.encryptUuid(toBan.get(0)), groupOperations.encryptUuid(toBan.get(1))));
|
||||
hasItems(groupOperations.encryptServiceId(ACI.from(toBan.get(0))),
|
||||
groupOperations.encryptServiceId(ACI.from(toBan.get(1)))));
|
||||
}
|
||||
}
|
||||
|
||||
+54
-52
@@ -33,6 +33,8 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedString;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedTimer;
|
||||
import org.signal.storageservice.protos.groups.local.EnabledState;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
import org.whispersystems.signalservice.testutil.LibSignalLibraryUtil;
|
||||
@@ -94,8 +96,8 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
|
||||
@Test
|
||||
public void can_decrypt_member_additions_field3() {
|
||||
UUID self = UUID.randomUUID();
|
||||
UUID newMember = UUID.randomUUID();
|
||||
ACI self = ACI.from(UUID.randomUUID());
|
||||
ACI newMember = ACI.from(UUID.randomUUID());
|
||||
ProfileKey profileKey = newProfileKey();
|
||||
GroupCandidate groupCandidate = groupCandidate(newMember, profileKey);
|
||||
|
||||
@@ -107,12 +109,12 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setJoinedAtRevision(10)
|
||||
.setUuid(UuidUtil.toByteString(newMember))));
|
||||
.setUuid(newMember.toByteString())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_member_direct_join_field3() {
|
||||
UUID newMember = UUID.randomUUID();
|
||||
ACI newMember = ACI.from(UUID.randomUUID());
|
||||
ProfileKey profileKey = newProfileKey();
|
||||
GroupCandidate groupCandidate = groupCandidate(newMember, profileKey);
|
||||
|
||||
@@ -124,13 +126,13 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setJoinedAtRevision(10)
|
||||
.setUuid(UuidUtil.toByteString(newMember))));
|
||||
.setUuid(newMember.toByteString())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_member_additions_direct_to_admin_field3() {
|
||||
UUID self = UUID.randomUUID();
|
||||
UUID newMember = UUID.randomUUID();
|
||||
ACI self = ACI.from(UUID.randomUUID());
|
||||
ACI newMember = ACI.from(UUID.randomUUID());
|
||||
ProfileKey profileKey = newProfileKey();
|
||||
GroupCandidate groupCandidate = groupCandidate(newMember, profileKey);
|
||||
|
||||
@@ -142,7 +144,7 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setJoinedAtRevision(10)
|
||||
.setUuid(UuidUtil.toByteString(newMember))));
|
||||
.setUuid(newMember.toByteString())));
|
||||
}
|
||||
|
||||
@Test(expected = InvalidGroupStateException.class)
|
||||
@@ -181,29 +183,29 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
|
||||
@Test
|
||||
public void can_decrypt_modify_member_action_role_to_admin_field5() {
|
||||
UUID member = UUID.randomUUID();
|
||||
ACI member = ACI.from(UUID.randomUUID());
|
||||
|
||||
assertDecryption(groupOperations.createChangeMemberRole(member, Member.Role.ADMINISTRATOR),
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(member))
|
||||
.setUuid(member.toByteString())
|
||||
.setRole(Member.Role.ADMINISTRATOR)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_modify_member_action_role_to_member_field5() {
|
||||
UUID member = UUID.randomUUID();
|
||||
ACI member = ACI.from(UUID.randomUUID());
|
||||
|
||||
assertDecryption(groupOperations.createChangeMemberRole(member, Member.Role.DEFAULT),
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.addModifyMemberRoles(DecryptedModifyMemberRole.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(member))
|
||||
.setUuid(member.toByteString())
|
||||
.setRole(Member.Role.DEFAULT)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_modify_member_profile_key_action_field6() {
|
||||
UUID self = UUID.randomUUID();
|
||||
ACI self = ACI.from(UUID.randomUUID());
|
||||
ProfileKey profileKey = newProfileKey();
|
||||
GroupCandidate groupCandidate = groupCandidate(self, profileKey);
|
||||
|
||||
@@ -215,35 +217,35 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
.setRole(Member.Role.UNKNOWN)
|
||||
.setJoinedAtRevision(-1)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setUuid(UuidUtil.toByteString(self))));
|
||||
.setUuid(self.toByteString())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_member_invitations_field7() {
|
||||
UUID self = UUID.randomUUID();
|
||||
UUID newMember = UUID.randomUUID();
|
||||
GroupCandidate groupCandidate = groupCandidate(newMember);
|
||||
ACI self = ACI.from(UUID.randomUUID());
|
||||
ACI newMember = ACI.from(UUID.randomUUID());
|
||||
GroupCandidate groupCandidate = new GroupCandidate(newMember, Optional.empty());
|
||||
|
||||
assertDecryption(groupOperations.createModifyGroupMembershipChange(Collections.singleton(groupCandidate), Collections.emptySet(), self)
|
||||
.setRevision(13),
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.setRevision(13)
|
||||
.addNewPendingMembers(DecryptedPendingMember.newBuilder()
|
||||
.setAddedByUuid(UuidUtil.toByteString(self))
|
||||
.setUuidCipherText(groupOperations.encryptUuid(newMember))
|
||||
.setAddedByUuid(self.toByteString())
|
||||
.setUuidCipherText(groupOperations.encryptServiceId(newMember))
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setUuid(UuidUtil.toByteString(newMember))));
|
||||
.setServiceIdBinary(newMember.toByteString())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_pending_member_removals_field8() throws InvalidInputException {
|
||||
UUID oldMember = UUID.randomUUID();
|
||||
UuidCiphertext uuidCiphertext = new UuidCiphertext(groupOperations.encryptUuid(oldMember).toByteArray());
|
||||
ACI oldMember = ACI.from(UUID.randomUUID());
|
||||
UuidCiphertext uuidCiphertext = new UuidCiphertext(groupOperations.encryptServiceId(oldMember).toByteArray());
|
||||
|
||||
assertDecryption(groupOperations.createRemoveInvitationChange(Collections.singleton(uuidCiphertext)),
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(oldMember))
|
||||
.setServiceIdBinary(oldMember.toByteString())
|
||||
.setUuidCipherText(ByteString.copyFrom(uuidCiphertext.serialize()))));
|
||||
}
|
||||
|
||||
@@ -257,20 +259,20 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
.setDeletedUserId(ByteString.copyFrom(uuidCiphertext))),
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.addDeletePendingMembers(DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(UuidUtil.UNKNOWN_UUID))
|
||||
.setServiceIdBinary(UuidUtil.toByteString(UuidUtil.UNKNOWN_UUID))
|
||||
.setUuidCipherText(ByteString.copyFrom(uuidCiphertext))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_promote_pending_member_field9() {
|
||||
UUID newMember = UUID.randomUUID();
|
||||
ACI newMember = ACI.from(UUID.randomUUID());
|
||||
ProfileKey profileKey = newProfileKey();
|
||||
GroupCandidate groupCandidate = groupCandidate(newMember, profileKey);
|
||||
|
||||
assertDecryption(groupOperations.createAcceptInviteChange(groupCandidate.getExpiringProfileKeyCredential().get()),
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.addPromotePendingMembers(DecryptedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(newMember))
|
||||
.setUuid(newMember.toByteString())
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setJoinedAtRevision(-1)));
|
||||
@@ -328,7 +330,7 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
|
||||
@Test
|
||||
public void can_decrypt_member_requests_field16() {
|
||||
UUID newRequestingMember = UUID.randomUUID();
|
||||
ACI newRequestingMember = ACI.from(UUID.randomUUID());
|
||||
ProfileKey profileKey = newProfileKey();
|
||||
GroupCandidate groupCandidate = groupCandidate(newRequestingMember, profileKey);
|
||||
|
||||
@@ -337,7 +339,7 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.setRevision(10)
|
||||
.addNewRequestingMembers(DecryptedRequestingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(newRequestingMember))
|
||||
.setUuid(newRequestingMember.toByteString())
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))));
|
||||
}
|
||||
|
||||
@@ -350,7 +352,7 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.setRevision(10)
|
||||
.addDeleteRequestingMembers(UuidUtil.toByteString(newRequestingMember))
|
||||
.addNewBannedMembers(DecryptedBannedMember.newBuilder().setUuid(UuidUtil.toByteString(newRequestingMember)).build()));
|
||||
.addNewBannedMembers(DecryptedBannedMember.newBuilder().setServiceIdBinary(UuidUtil.toByteString(newRequestingMember)).build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -402,42 +404,42 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.setRevision(13)
|
||||
.addNewBannedMembers(DecryptedBannedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(ban))));
|
||||
.setServiceIdBinary(UuidUtil.toByteString(ban))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_banned_member_removals_field23() {
|
||||
UUID ban = UUID.randomUUID();
|
||||
ACI ban = ACI.from(UUID.randomUUID());
|
||||
|
||||
assertDecryption(groupOperations.createUnbanUuidsChange(Collections.singleton(ban))
|
||||
assertDecryption(groupOperations.createUnbanServiceIdsChange(Collections.singleton(ban))
|
||||
.setRevision(13),
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.setRevision(13)
|
||||
.addDeleteBannedMembers(DecryptedBannedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(ban))));
|
||||
.setServiceIdBinary(ban.toByteString())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void can_decrypt_promote_pending_pni_aci_member_field24() {
|
||||
UUID memberUuid = UUID.randomUUID();
|
||||
UUID memberPni = UUID.randomUUID();
|
||||
ACI memberAci = ACI.from(UUID.randomUUID());
|
||||
PNI memberPni = PNI.from(UUID.randomUUID());
|
||||
ProfileKey profileKey = newProfileKey();
|
||||
|
||||
GroupChange.Actions.Builder builder = GroupChange.Actions.newBuilder()
|
||||
.setSourceUuid(groupOperations.encryptUuid(memberPni))
|
||||
.setSourceUuid(groupOperations.encryptServiceId(memberPni))
|
||||
.setRevision(5)
|
||||
.addPromotePendingPniAciMembers(GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction.newBuilder()
|
||||
.setUserId(groupOperations.encryptUuid(memberUuid))
|
||||
.setPni(groupOperations.encryptUuid(memberPni))
|
||||
.setProfileKey(encryptProfileKey(memberUuid, profileKey)));
|
||||
.setUserId(groupOperations.encryptServiceId(memberAci))
|
||||
.setPni(groupOperations.encryptServiceId(memberPni))
|
||||
.setProfileKey(encryptProfileKey(memberAci, profileKey)));
|
||||
|
||||
assertDecryptionWithEditorSet(builder,
|
||||
DecryptedGroupChange.newBuilder()
|
||||
.setEditor(UuidUtil.toByteString(memberUuid))
|
||||
.setEditor(memberAci.toByteString())
|
||||
.setRevision(5)
|
||||
.addPromotePendingPniAciMembers(DecryptedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(memberUuid))
|
||||
.setPni(UuidUtil.toByteString(memberPni))
|
||||
.setUuid(memberAci.toByteString())
|
||||
.setPni(memberPni.toByteString())
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setJoinedAtRevision(5)));
|
||||
@@ -451,23 +453,23 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
}
|
||||
}
|
||||
|
||||
private ByteString encryptProfileKey(UUID uuid, ProfileKey profileKey) {
|
||||
return ByteString.copyFrom(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, uuid).serialize());
|
||||
private ByteString encryptProfileKey(ACI aci, ProfileKey profileKey) {
|
||||
return ByteString.copyFrom(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, aci.getLibSignalAci()).serialize());
|
||||
}
|
||||
|
||||
static GroupCandidate groupCandidate(UUID uuid) {
|
||||
return new GroupCandidate(uuid, Optional.empty());
|
||||
return new GroupCandidate(ACI.from(uuid), Optional.empty());
|
||||
}
|
||||
|
||||
GroupCandidate groupCandidate(UUID uuid, ProfileKey profileKey) {
|
||||
GroupCandidate groupCandidate(ACI aci, ProfileKey profileKey) {
|
||||
try {
|
||||
ClientZkProfileOperations profileOperations = clientZkOperations.getProfileOperations();
|
||||
ProfileKeyCommitment commitment = profileKey.getCommitment(uuid);
|
||||
ProfileKeyCredentialRequestContext requestContext = profileOperations.createProfileKeyCredentialRequestContext(uuid, profileKey);
|
||||
ProfileKeyCommitment commitment = profileKey.getCommitment(aci.getLibSignalAci());
|
||||
ProfileKeyCredentialRequestContext requestContext = profileOperations.createProfileKeyCredentialRequestContext(aci.getLibSignalAci(), profileKey);
|
||||
ProfileKeyCredentialRequest request = requestContext.getRequest();
|
||||
ExpiringProfileKeyCredentialResponse expiringProfileKeyCredentialResponse = server.getExpiringProfileKeyCredentialResponse(request, uuid, commitment, Instant.now().plus(7, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS));
|
||||
ExpiringProfileKeyCredentialResponse expiringProfileKeyCredentialResponse = server.getExpiringProfileKeyCredentialResponse(request, aci, commitment, Instant.now().plus(7, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS));
|
||||
ExpiringProfileKeyCredential profileKeyCredential = profileOperations.receiveExpiringProfileKeyCredential(requestContext, expiringProfileKeyCredentialResponse);
|
||||
GroupCandidate groupCandidate = new GroupCandidate(uuid, Optional.of(profileKeyCredential));
|
||||
GroupCandidate groupCandidate = new GroupCandidate(aci, Optional.of(profileKeyCredential));
|
||||
|
||||
ProfileKeyCredentialPresentation presentation = profileOperations.createProfileKeyCredentialPresentation(groupSecretParams, profileKeyCredential);
|
||||
server.assertProfileKeyCredentialPresentation(groupSecretParams.getPublicParams(), presentation, Instant.now());
|
||||
@@ -481,8 +483,8 @@ public final class GroupsV2Operations_decrypt_change_Test {
|
||||
void assertDecryption(GroupChange.Actions.Builder inputChange,
|
||||
DecryptedGroupChange.Builder expectedDecrypted)
|
||||
{
|
||||
UUID editor = UUID.randomUUID();
|
||||
assertDecryptionWithEditorSet(inputChange.setSourceUuid(groupOperations.encryptUuid(editor)), expectedDecrypted.setEditor(UuidUtil.toByteString(editor)));
|
||||
ACI editor = ACI.from(UUID.randomUUID());
|
||||
assertDecryptionWithEditorSet(inputChange.setSourceUuid(groupOperations.encryptServiceId(editor)), expectedDecrypted.setEditor(editor.toByteString()));
|
||||
}
|
||||
|
||||
void assertDecryptionWithEditorSet(GroupChange.Actions.Builder inputChange,
|
||||
|
||||
+38
-38
@@ -22,7 +22,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
|
||||
import org.signal.storageservice.protos.groups.local.EnabledState;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
import org.whispersystems.signalservice.testutil.LibSignalLibraryUtil;
|
||||
|
||||
@@ -122,20 +122,20 @@ public final class GroupsV2Operations_decrypt_group_Test {
|
||||
|
||||
@Test
|
||||
public void decrypt_full_members_field_7() throws VerificationFailedException, InvalidGroupStateException {
|
||||
UUID admin1 = UUID.randomUUID();
|
||||
UUID member1 = UUID.randomUUID();
|
||||
ACI admin1 = ACI.from(UUID.randomUUID());
|
||||
ACI member1 = ACI.from(UUID.randomUUID());
|
||||
ProfileKey adminProfileKey = newProfileKey();
|
||||
ProfileKey memberProfileKey = newProfileKey();
|
||||
|
||||
Group group = Group.newBuilder()
|
||||
.addMembers(Member.newBuilder()
|
||||
.setRole(Member.Role.ADMINISTRATOR)
|
||||
.setUserId(groupOperations.encryptUuid(admin1))
|
||||
.setUserId(groupOperations.encryptServiceId(admin1))
|
||||
.setJoinedAtRevision(4)
|
||||
.setProfileKey(encryptProfileKey(admin1, adminProfileKey)))
|
||||
.addMembers(Member.newBuilder()
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setUserId(groupOperations.encryptUuid(member1))
|
||||
.setUserId(groupOperations.encryptServiceId(member1))
|
||||
.setJoinedAtRevision(7)
|
||||
.setProfileKey(encryptProfileKey(member1, memberProfileKey)))
|
||||
.build();
|
||||
@@ -145,13 +145,13 @@ public final class GroupsV2Operations_decrypt_group_Test {
|
||||
assertEquals(DecryptedGroup.newBuilder()
|
||||
.addMembers(DecryptedMember.newBuilder()
|
||||
.setJoinedAtRevision(4)
|
||||
.setUuid(UuidUtil.toByteString(admin1))
|
||||
.setUuid(admin1.toByteString())
|
||||
.setRole(Member.Role.ADMINISTRATOR)
|
||||
.setProfileKey(ByteString.copyFrom(adminProfileKey.serialize())))
|
||||
.addMembers(DecryptedMember.newBuilder()
|
||||
.setJoinedAtRevision(7)
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setUuid(UuidUtil.toByteString(member1))
|
||||
.setUuid(member1.toByteString())
|
||||
.setProfileKey(ByteString.copyFrom(memberProfileKey.serialize())))
|
||||
.build().getMembersList(),
|
||||
decryptedGroup.getMembersList());
|
||||
@@ -159,52 +159,52 @@ public final class GroupsV2Operations_decrypt_group_Test {
|
||||
|
||||
@Test
|
||||
public void decrypt_pending_members_field_8() throws VerificationFailedException, InvalidGroupStateException {
|
||||
UUID admin1 = UUID.randomUUID();
|
||||
UUID member1 = UUID.randomUUID();
|
||||
UUID member2 = UUID.randomUUID();
|
||||
UUID inviter1 = UUID.randomUUID();
|
||||
UUID inviter2 = UUID.randomUUID();
|
||||
ACI admin1 = ACI.from(UUID.randomUUID());
|
||||
ACI member1 = ACI.from(UUID.randomUUID());
|
||||
ACI member2 = ACI.from(UUID.randomUUID());
|
||||
ACI inviter1 = ACI.from(UUID.randomUUID());
|
||||
ACI inviter2 = ACI.from(UUID.randomUUID());
|
||||
|
||||
Group group = Group.newBuilder()
|
||||
.addPendingMembers(PendingMember.newBuilder()
|
||||
.setAddedByUserId(groupOperations.encryptUuid(inviter1))
|
||||
.setAddedByUserId(groupOperations.encryptServiceId(inviter1))
|
||||
.setTimestamp(100)
|
||||
.setMember(Member.newBuilder()
|
||||
.setRole(Member.Role.ADMINISTRATOR)
|
||||
.setUserId(groupOperations.encryptUuid(admin1))))
|
||||
.setUserId(groupOperations.encryptServiceId(admin1))))
|
||||
.addPendingMembers(PendingMember.newBuilder()
|
||||
.setAddedByUserId(groupOperations.encryptUuid(inviter1))
|
||||
.setAddedByUserId(groupOperations.encryptServiceId(inviter1))
|
||||
.setTimestamp(200)
|
||||
.setMember(Member.newBuilder()
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.setUserId(groupOperations.encryptUuid(member1))))
|
||||
.setUserId(groupOperations.encryptServiceId(member1))))
|
||||
.addPendingMembers(PendingMember.newBuilder()
|
||||
.setAddedByUserId(groupOperations.encryptUuid(inviter2))
|
||||
.setAddedByUserId(groupOperations.encryptServiceId(inviter2))
|
||||
.setTimestamp(1500)
|
||||
.setMember(Member.newBuilder()
|
||||
.setUserId(groupOperations.encryptUuid(member2))))
|
||||
.setUserId(groupOperations.encryptServiceId(member2))))
|
||||
.build();
|
||||
|
||||
DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group);
|
||||
|
||||
assertEquals(DecryptedGroup.newBuilder()
|
||||
.addPendingMembers(DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(admin1))
|
||||
.setUuidCipherText(groupOperations.encryptUuid(admin1))
|
||||
.setServiceIdBinary(admin1.toByteString())
|
||||
.setUuidCipherText(groupOperations.encryptServiceId(admin1))
|
||||
.setTimestamp(100)
|
||||
.setAddedByUuid(UuidUtil.toByteString(inviter1))
|
||||
.setAddedByUuid(inviter1.toByteString())
|
||||
.setRole(Member.Role.ADMINISTRATOR))
|
||||
.addPendingMembers(DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(member1))
|
||||
.setUuidCipherText(groupOperations.encryptUuid(member1))
|
||||
.setServiceIdBinary(member1.toByteString())
|
||||
.setUuidCipherText(groupOperations.encryptServiceId(member1))
|
||||
.setTimestamp(200)
|
||||
.setAddedByUuid(UuidUtil.toByteString(inviter1))
|
||||
.setAddedByUuid(inviter1.toByteString())
|
||||
.setRole(Member.Role.DEFAULT))
|
||||
.addPendingMembers(DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(member2))
|
||||
.setUuidCipherText(groupOperations.encryptUuid(member2))
|
||||
.setServiceIdBinary(member2.toByteString())
|
||||
.setUuidCipherText(groupOperations.encryptServiceId(member2))
|
||||
.setTimestamp(1500)
|
||||
.setAddedByUuid(UuidUtil.toByteString(inviter2))
|
||||
.setAddedByUuid(inviter2.toByteString())
|
||||
.setRole(Member.Role.DEFAULT))
|
||||
.build().getPendingMembersList(),
|
||||
decryptedGroup.getPendingMembersList());
|
||||
@@ -212,18 +212,18 @@ public final class GroupsV2Operations_decrypt_group_Test {
|
||||
|
||||
@Test
|
||||
public void decrypt_requesting_members_field_9() throws VerificationFailedException, InvalidGroupStateException {
|
||||
UUID admin1 = UUID.randomUUID();
|
||||
UUID member1 = UUID.randomUUID();
|
||||
ACI admin1 = ACI.from(UUID.randomUUID());
|
||||
ACI member1 = ACI.from(UUID.randomUUID());
|
||||
ProfileKey adminProfileKey = newProfileKey();
|
||||
ProfileKey memberProfileKey = newProfileKey();
|
||||
|
||||
Group group = Group.newBuilder()
|
||||
.addRequestingMembers(RequestingMember.newBuilder()
|
||||
.setUserId(groupOperations.encryptUuid(admin1))
|
||||
.setUserId(groupOperations.encryptServiceId(admin1))
|
||||
.setProfileKey(encryptProfileKey(admin1, adminProfileKey))
|
||||
.setTimestamp(5000))
|
||||
.addRequestingMembers(RequestingMember.newBuilder()
|
||||
.setUserId(groupOperations.encryptUuid(member1))
|
||||
.setUserId(groupOperations.encryptServiceId(member1))
|
||||
.setProfileKey(encryptProfileKey(member1, memberProfileKey))
|
||||
.setTimestamp(15000))
|
||||
.build();
|
||||
@@ -232,11 +232,11 @@ public final class GroupsV2Operations_decrypt_group_Test {
|
||||
|
||||
assertEquals(DecryptedGroup.newBuilder()
|
||||
.addRequestingMembers(DecryptedRequestingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(admin1))
|
||||
.setUuid(admin1.toByteString())
|
||||
.setProfileKey(ByteString.copyFrom(adminProfileKey.serialize()))
|
||||
.setTimestamp(5000))
|
||||
.addRequestingMembers(DecryptedRequestingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(member1))
|
||||
.setUuid(member1.toByteString())
|
||||
.setProfileKey(ByteString.copyFrom(memberProfileKey.serialize()))
|
||||
.setTimestamp(15000))
|
||||
.build().getRequestingMembersList(),
|
||||
@@ -279,20 +279,20 @@ public final class GroupsV2Operations_decrypt_group_Test {
|
||||
|
||||
@Test
|
||||
public void decrypt_banned_members_field_13() throws VerificationFailedException, InvalidGroupStateException {
|
||||
UUID member1 = UUID.randomUUID();
|
||||
ACI member1 = ACI.from(UUID.randomUUID());
|
||||
|
||||
Group group = Group.newBuilder()
|
||||
.addBannedMembers(BannedMember.newBuilder().setUserId(groupOperations.encryptUuid(member1)))
|
||||
.addBannedMembers(BannedMember.newBuilder().setUserId(groupOperations.encryptServiceId(member1)))
|
||||
.build();
|
||||
|
||||
DecryptedGroup decryptedGroup = groupOperations.decryptGroup(group);
|
||||
|
||||
assertEquals(1, decryptedGroup.getBannedMembersCount());
|
||||
assertEquals(DecryptedBannedMember.newBuilder().setUuid(UuidUtil.toByteString(member1)).build(), decryptedGroup.getBannedMembers(0));
|
||||
assertEquals(DecryptedBannedMember.newBuilder().setServiceIdBinary(member1.toByteString()).build(), decryptedGroup.getBannedMembers(0));
|
||||
}
|
||||
|
||||
private ByteString encryptProfileKey(UUID uuid, ProfileKey profileKey) {
|
||||
return ByteString.copyFrom(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, uuid).serialize());
|
||||
private ByteString encryptProfileKey(ACI aci, ProfileKey profileKey) {
|
||||
return ByteString.copyFrom(new ClientZkGroupCipher(groupSecretParams).encryptProfileKey(profileKey, aci.getLibSignalAci()).serialize());
|
||||
}
|
||||
|
||||
private static ProfileKey newProfileKey() {
|
||||
|
||||
+3
-3
@@ -107,14 +107,14 @@ final class ProtoTestUtils {
|
||||
|
||||
static DecryptedPendingMemberRemoval pendingMemberRemoval(UUID uuid) {
|
||||
return DecryptedPendingMemberRemoval.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setServiceIdBinary(UuidUtil.toByteString(uuid))
|
||||
.setUuidCipherText(encrypt(uuid))
|
||||
.build();
|
||||
}
|
||||
|
||||
static DecryptedPendingMember pendingMember(UUID uuid) {
|
||||
return DecryptedPendingMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setServiceIdBinary(UuidUtil.toByteString(uuid))
|
||||
.setUuidCipherText(encrypt(uuid))
|
||||
.setRole(Member.Role.DEFAULT)
|
||||
.build();
|
||||
@@ -133,7 +133,7 @@ final class ProtoTestUtils {
|
||||
|
||||
static DecryptedBannedMember bannedMember(UUID uuid) {
|
||||
return DecryptedBannedMember.newBuilder()
|
||||
.setUuid(UuidUtil.toByteString(uuid))
|
||||
.setServiceIdBinary(UuidUtil.toByteString(uuid))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -9,10 +9,10 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKeyCommitment;
|
||||
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialPresentation;
|
||||
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialRequest;
|
||||
import org.signal.libsignal.zkgroup.profiles.ServerZkProfileOperations;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.testutil.LibSignalLibraryUtil;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Provides Zk group operations that the server would provide.
|
||||
@@ -35,8 +35,8 @@ final class TestZkGroupServer {
|
||||
return serverPublicParams;
|
||||
}
|
||||
|
||||
public ExpiringProfileKeyCredentialResponse getExpiringProfileKeyCredentialResponse(ProfileKeyCredentialRequest request, UUID uuid, ProfileKeyCommitment commitment, Instant expiration) throws VerificationFailedException {
|
||||
return serverZkProfileOperations.issueExpiringProfileKeyCredential(request, uuid, commitment, expiration);
|
||||
public ExpiringProfileKeyCredentialResponse getExpiringProfileKeyCredentialResponse(ProfileKeyCredentialRequest request, ACI aci, ProfileKeyCommitment commitment, Instant expiration) throws VerificationFailedException {
|
||||
return serverZkProfileOperations.issueExpiringProfileKeyCredential(request, aci.getLibSignalAci(), commitment, expiration);
|
||||
}
|
||||
|
||||
public void assertProfileKeyCredentialPresentation(GroupPublicParams publicParams, ProfileKeyCredentialPresentation profileKeyCredentialPresentation, Instant now) {
|
||||
|
||||
Reference in New Issue
Block a user