mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-02 16:32:57 +01:00
Show group update messages for member label permission changes.
This commit is contained in:
@@ -15,10 +15,10 @@ import org.signal.benchmark.setup.Generator
|
||||
import org.signal.benchmark.setup.Harness
|
||||
import org.signal.benchmark.setup.OtherClient
|
||||
import org.signal.core.util.ThreadUtil
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.TestDbUtils
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.whispersystems.signalservice.internal.push.Envelope
|
||||
|
||||
@@ -13,7 +13,6 @@ import kotlinx.coroutines.launch
|
||||
import org.signal.benchmark.setup.Harness
|
||||
import org.signal.benchmark.setup.TestMessages
|
||||
import org.signal.benchmark.setup.TestUsers
|
||||
import org.signal.core.models.ServiceId.PNI
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.BaseActivity
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupRepository
|
||||
|
||||
@@ -43,7 +43,6 @@ import org.signal.core.util.delete
|
||||
import org.signal.core.util.deleteAll
|
||||
import org.signal.core.util.exists
|
||||
import org.signal.core.util.forEach
|
||||
import org.signal.core.util.forceForeignKeyConstraintsEnabled
|
||||
import org.signal.core.util.insertInto
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.readToList
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberAddedUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedByLinkUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLabelAccessLevelChangeUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLeftUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberRemovedUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMembershipAccessLevelChangeUpdate
|
||||
@@ -146,6 +147,7 @@ object GroupsV2UpdateMessageConverter {
|
||||
translateNewTimer(change, editorUnknown, updates)
|
||||
translateNewAttributeAccess(change, editorUnknown, updates)
|
||||
translateNewMembershipAccess(change, editorUnknown, updates)
|
||||
translateNewMemberLabelAccess(change, editorUnknown, updates)
|
||||
translateNewGroupInviteLinkAccess(previousGroupState, change, editorUnknown, updates)
|
||||
translateRequestingMembers(selfIds, change, editorUnknown, updates)
|
||||
translateRequestingMemberApprovals(selfIds, change, editorUnknown, updates)
|
||||
@@ -437,6 +439,21 @@ object GroupsV2UpdateMessageConverter {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewMemberLabelAccess(change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
if (change.newMemberLabelAccess !== AccessRequired.UNKNOWN) {
|
||||
val editorAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupMemberLabelAccessLevelChangeUpdate = GroupMemberLabelAccessLevelChangeUpdate(
|
||||
updaterAci = editorAci,
|
||||
accessLevel = translateGv2AccessLevel(change.newMemberLabelAccess)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun translateNewGroupInviteLinkAccess(previousGroupState: DecryptedGroup?, change: DecryptedGroupChange, editorUnknown: Boolean, updates: MutableList<GroupChangeChatUpdate.Update>) {
|
||||
var previousAccessControl: AccessRequired? = null
|
||||
|
||||
@@ -11,7 +11,9 @@ import androidx.annotation.StringRes;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.signal.core.models.ServiceId;
|
||||
import org.signal.core.util.BidiUtil;
|
||||
import org.signal.core.util.UuidUtil;
|
||||
import org.signal.storageservice.storage.protos.groups.AccessControl;
|
||||
import org.signal.storageservice.storage.protos.groups.Member;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedApproveMember;
|
||||
@@ -46,6 +48,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberAddedUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedByLinkUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLabelAccessLevelChangeUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLeftUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberRemovedUpdate;
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupMembershipAccessLevelChangeUpdate;
|
||||
@@ -66,9 +69,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.signal.core.models.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.ServiceIds;
|
||||
import org.signal.core.util.UuidUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -165,6 +166,8 @@ final class GroupsV2UpdateMessageProducer {
|
||||
describeGroupMembershipAccessLevelChange(update.groupMembershipAccessLevelChangeUpdate, updates);
|
||||
} else if (update.groupAttributesAccessLevelChangeUpdate != null) {
|
||||
describeGroupAttributesAccessLevelChange(update.groupAttributesAccessLevelChangeUpdate, updates);
|
||||
} else if (update.groupMemberLabelAccessLevelChangeUpdate != null) {
|
||||
describeGroupMemberLabelAccessLevelChange(update.groupMemberLabelAccessLevelChangeUpdate, updates);
|
||||
} else if (update.groupAnnouncementOnlyChangeUpdate != null) {
|
||||
describeGroupAnnouncementOnlyUpdate(update.groupAnnouncementOnlyChangeUpdate, updates);
|
||||
} else if (update.groupAdminStatusUpdate != null) {
|
||||
@@ -592,6 +595,24 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
}
|
||||
|
||||
private void describeGroupMemberLabelAccessLevelChange(@NonNull GroupMemberLabelAccessLevelChangeUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||
if (update.accessLevel == GroupV2AccessLevel.UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
String accessLevel = GV2AccessLevelUtil.toString(context, backupGv2AccessLevelToGroups(update.accessLevel));
|
||||
if (update.updaterAci == null) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_unknown_admin_changed_who_can_add_member_labels_to_s, accessLevel), Glyph.MEGAPHONE));
|
||||
} else {
|
||||
boolean editorIsYou = selfIds.matches(update.updaterAci);
|
||||
if (editorIsYou) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_add_member_labels_to_s, accessLevel), Glyph.MEGAPHONE));
|
||||
} else {
|
||||
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_add_member_labels_to_s, update.updaterAci, accessLevel, Glyph.MEGAPHONE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void describeGroupAnnouncementOnlyUpdate(@NonNull GroupAnnouncementOnlyChangeUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||
if (update.updaterAci == null) {
|
||||
if (update.isAnnouncementOnly) {
|
||||
@@ -707,6 +728,7 @@ final class GroupsV2UpdateMessageProducer {
|
||||
describeUnknownEditorNewTimer(change, updates);
|
||||
describeUnknownEditorNewAttributeAccess(change, updates);
|
||||
describeUnknownEditorNewMembershipAccess(change, updates);
|
||||
describeUnknownEditorNewMemberLabelAccess(change, updates);
|
||||
describeUnknownEditorNewGroupInviteLinkAccess(previousGroupState, change, updates);
|
||||
describeRequestingMembers(change, updates);
|
||||
describeUnknownEditorRequestingMembersApprovals(change, updates);
|
||||
@@ -733,6 +755,7 @@ final class GroupsV2UpdateMessageProducer {
|
||||
describeNewTimer(change, updates);
|
||||
describeNewAttributeAccess(change, updates);
|
||||
describeNewMembershipAccess(change, updates);
|
||||
describeNewMemberLabelAccess(change, updates);
|
||||
describeNewGroupInviteLinkAccess(previousGroupState, change, updates);
|
||||
describeRequestingMembers(change, updates);
|
||||
describeRequestingMembersApprovals(change, updates);
|
||||
@@ -1223,6 +1246,26 @@ final class GroupsV2UpdateMessageProducer {
|
||||
}
|
||||
}
|
||||
|
||||
private void describeNewMemberLabelAccess(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
||||
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
|
||||
|
||||
if (change.newMemberLabelAccess != AccessControl.AccessRequired.UNKNOWN) {
|
||||
String accessLevel = GV2AccessLevelUtil.toString(context, change.newMemberLabelAccess);
|
||||
if (editorIsYou) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_add_member_labels_to_s, accessLevel), Glyph.MEGAPHONE));
|
||||
} else {
|
||||
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_add_member_labels_to_s, change.editorServiceIdBytes, accessLevel, Glyph.MEGAPHONE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void describeUnknownEditorNewMemberLabelAccess(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
|
||||
if (change.newMemberLabelAccess != AccessControl.AccessRequired.UNKNOWN) {
|
||||
String accessLevel = GV2AccessLevelUtil.toString(context, change.newMemberLabelAccess);
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_unknown_admin_changed_who_can_add_member_labels_to_s, accessLevel), Glyph.MEGAPHONE));
|
||||
}
|
||||
}
|
||||
|
||||
private void describeNewGroupInviteLinkAccess(@Nullable DecryptedGroup previousGroupState,
|
||||
@NonNull DecryptedGroupChange change,
|
||||
@NonNull List<UpdateDescription> updates)
|
||||
|
||||
@@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.notifications.NotificationIds
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.SignalTrace
|
||||
import org.thoughtcrime.securesms.util.asChain
|
||||
import org.whispersystems.signalservice.api.InvalidMessageStructureException
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint
|
||||
@@ -73,7 +74,6 @@ import org.whispersystems.signalservice.internal.push.Content
|
||||
import org.whispersystems.signalservice.internal.push.Envelope
|
||||
import org.whispersystems.signalservice.internal.push.PniSignatureMessage
|
||||
import org.whispersystems.signalservice.internal.util.Util
|
||||
import org.thoughtcrime.securesms.util.SignalTrace
|
||||
import java.util.Optional
|
||||
import kotlin.time.Duration.Companion.nanoseconds
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
@@ -2022,6 +2022,13 @@
|
||||
<string name="MessageRecord_s_changed_who_can_edit_group_membership_to_s">%1$s changed who can edit group membership to \"%2$s\".</string>
|
||||
<string name="MessageRecord_who_can_edit_group_membership_has_been_changed_to_s">Who can edit group membership has been changed to \"%1$s\".</string>
|
||||
|
||||
<!-- Shown when the current user changes the member label permission. -->
|
||||
<string name="MessageRecord_you_changed_who_can_add_member_labels_to_s">You changed who can add member labels to \"%1$s\".</string>
|
||||
<!-- Shown when another group member changes the member label permission. -->
|
||||
<string name="MessageRecord_s_changed_who_can_add_member_labels_to_s">%1$s changed who can add member labels to \"%2$s\".</string>
|
||||
<!-- Shown when the member label permission is changed by an unknown admin. -->
|
||||
<string name="MessageRecord_unknown_admin_changed_who_can_add_member_labels_to_s">An admin changed who can add member labels to \"%1$s\".</string>
|
||||
|
||||
<!-- GV2 announcement group change -->
|
||||
<string name="MessageRecord_you_allow_all_members_to_send">You changed the group settings to allow all members to send messages.</string>
|
||||
<string name="MessageRecord_you_allow_only_admins_to_send">You changed the group settings to only allow admins to send messages.</string>
|
||||
|
||||
@@ -824,6 +824,34 @@ class GroupsV2UpdateMessageProducerTest {
|
||||
assertEquals(listOf("Who can edit group membership has been changed to \"Only admins\"."), describeChange(change))
|
||||
}
|
||||
|
||||
// member label access change
|
||||
@Test
|
||||
fun member_changes_member_label_access() {
|
||||
val change = ChangeBuilder.changeBy(bob)
|
||||
.memberLabelAccess(MEMBER)
|
||||
.build()
|
||||
|
||||
assertEquals(listOf("Bob changed who can add member labels to \"All members\"."), describeChange(change))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun you_changed_member_label_access() {
|
||||
val change = ChangeBuilder.changeBy(you)
|
||||
.memberLabelAccess(ADMINISTRATOR)
|
||||
.build()
|
||||
|
||||
assertEquals(listOf("You changed who can add member labels to \"Only admins\"."), describeChange(change))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unknown_changed_member_label_access() {
|
||||
val change = ChangeBuilder.changeByUnknown()
|
||||
.memberLabelAccess(ADMINISTRATOR)
|
||||
.build()
|
||||
|
||||
assertEquals(listOf("An admin changed who can add member labels to \"Only admins\"."), describeChange(change))
|
||||
}
|
||||
|
||||
// Group link access change
|
||||
@Test
|
||||
fun you_changed_group_link_access_to_any() {
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.groups.v2;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.models.ServiceId.ACI;
|
||||
import org.signal.core.util.Util;
|
||||
import org.signal.libsignal.zkgroup.InvalidInputException;
|
||||
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
||||
import org.signal.storageservice.storage.protos.groups.AccessControl;
|
||||
@@ -16,8 +18,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMem
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedRequestingMember;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
|
||||
import org.signal.core.util.Util;
|
||||
import org.signal.core.models.ServiceId.ACI;
|
||||
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import okio.ByteString;
|
||||
@@ -128,6 +128,11 @@ public final class ChangeBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChangeBuilder memberLabelAccess(@NonNull AccessControl.AccessRequired accessRequired) {
|
||||
builder.newMemberLabelAccess(accessRequired);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChangeBuilder inviteLinkAccess(@NonNull AccessControl.AccessRequired accessRequired) {
|
||||
builder.newInviteLinkAccess(accessRequired);
|
||||
return this;
|
||||
|
||||
Reference in New Issue
Block a user