mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-02 00:17:41 +01:00
Add additional checks for terminated groups during send flows.
This commit is contained in:
@@ -108,6 +108,11 @@ class AdminDeleteSendJob private constructor(
|
||||
}
|
||||
|
||||
val groupRecord = SignalDatabase.groups.getGroup(conversationRecipient.requireGroupId())
|
||||
if (groupRecord.isPresent && groupRecord.get().isTerminated) {
|
||||
Log.w(TAG, "Cannot admin delete in a terminated group.")
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
if (groupRecord.isEmpty || !groupRecord.get().isAdmin(Recipient.self())) {
|
||||
Log.w(TAG, "Cannot delete because you are not an admin.")
|
||||
return Result.failure()
|
||||
|
||||
@@ -7,9 +7,10 @@ import androidx.annotation.WorkerThread;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint;
|
||||
import org.thoughtcrime.securesms.messages.GroupSendUtil;
|
||||
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
|
||||
@@ -121,6 +122,11 @@ public class GroupCallUpdateSendJob extends BaseJob {
|
||||
throw new AssertionError("We have a recipient, but it's not a V2 Group");
|
||||
}
|
||||
|
||||
if (!SignalDatabase.groups().isActive(conversationRecipient.requireGroupId())) {
|
||||
Log.w(TAG, "Not sending group call update to terminated or inactive group.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Recipient> destinations = Stream.of(recipients).map(Recipient::resolved).toList();
|
||||
List<Recipient> completions = deliver(conversationRecipient, destinations);
|
||||
|
||||
|
||||
@@ -101,6 +101,11 @@ class PollVoteJob(
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
if (conversationRecipient.isPushV2Group && !SignalDatabase.groups.isActive(conversationRecipient.requireGroupId())) {
|
||||
Log.w(TAG, "Cannot send poll vote to terminated or inactive group.")
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
val poll = SignalDatabase.polls.getPoll(messageId)
|
||||
if (poll == null) {
|
||||
Log.w(TAG, "Unable to find corresponding poll")
|
||||
|
||||
@@ -169,6 +169,11 @@ public class ReactionSendJob extends BaseJob {
|
||||
return;
|
||||
}
|
||||
|
||||
if (conversationRecipient.isPushV2Group() && !SignalDatabase.groups().isActive(conversationRecipient.requireGroupId())) {
|
||||
Log.w(TAG, "Cannot send reactions to terminated or inactive groups.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Recipient> resolved = recipients.stream().map(Recipient::resolved).collect(Collectors.toList());
|
||||
List<RecipientId> unregistered = resolved.stream().filter(Recipient::isUnregistered).map(Recipient::getId).collect(Collectors.toList());
|
||||
List<Recipient> destinations = resolved.stream().filter(Recipient::isMaybeRegistered).collect(Collectors.toList());
|
||||
|
||||
@@ -153,6 +153,11 @@ public class RemoteDeleteSendJob extends BaseJob {
|
||||
return;
|
||||
}
|
||||
|
||||
if (conversationRecipient.isPushV2Group() && !SignalDatabase.groups().isActive(conversationRecipient.requireGroupId())) {
|
||||
Log.w(TAG, "Unable to remote delete messages in terminated or inactive groups");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Recipient> possible = Stream.of(recipients).map(Recipient::resolved).toList();
|
||||
List<Recipient> eligible = RecipientUtil.getEligibleForSending(Stream.of(recipients).map(Recipient::resolved).filter(Recipient::getHasServiceId).toList());
|
||||
List<RecipientId> skipped = Stream.of(SetUtil.difference(possible, eligible)).map(Recipient::getId).toList();
|
||||
|
||||
@@ -109,6 +109,11 @@ public class TypingSendJob extends BaseJob {
|
||||
return;
|
||||
}
|
||||
|
||||
if (recipient.isPushV2Group() && !SignalDatabase.groups().isActive(recipient.requireGroupId())) {
|
||||
Log.w(TAG, "Not sending typing indicators to terminated or inactive groups.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!recipient.isRegistered()) {
|
||||
Log.w(TAG, "Not sending typing indicators to non-Signal recipients.");
|
||||
return;
|
||||
|
||||
@@ -109,6 +109,10 @@ class UnpinMessageJob(
|
||||
|
||||
if (conversationRecipient.isPushV2Group) {
|
||||
val groupRecord = SignalDatabase.groups.getGroup(conversationRecipient.id)
|
||||
if (groupRecord.isPresent && groupRecord.get().isTerminated) {
|
||||
Log.w(TAG, "Cannot send unpin messages to terminated group.")
|
||||
return Result.failure()
|
||||
}
|
||||
if (groupRecord.isPresent && groupRecord.get().attributesAccessControl == GroupAccessControl.ONLY_ADMINS && !groupRecord.get().isAdmin(self())) {
|
||||
Log.w(TAG, "Non-admins cannot send unpin messages to group.")
|
||||
return Result.failure()
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.attachments.Attachment
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentSaver
|
||||
import org.thoughtcrime.securesms.components.menu.ActionItem
|
||||
import org.thoughtcrime.securesms.components.menu.SignalContextMenu
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
|
||||
@@ -40,14 +41,26 @@ object StoryContextMenu {
|
||||
|
||||
private val TAG = Log.tag(StoryContextMenu::class.java)
|
||||
|
||||
fun delete(context: Context, records: Set<MessageRecord>): Single<Boolean> {
|
||||
return DeleteDialog.show(
|
||||
context = context,
|
||||
messageRecords = records,
|
||||
title = context.getString(R.string.MyStories__delete_story),
|
||||
message = context.getString(R.string.MyStories__this_story_will_be_deleted),
|
||||
forceRemoteDelete = true
|
||||
).map { (_, deletedThread) -> deletedThread }
|
||||
fun delete(context: Context, record: MessageRecord): Single<Boolean> {
|
||||
val recipient = record.toRecipient
|
||||
val isGroupTerminated = recipient.isPushV2Group && !SignalDatabase.groups.isActive(recipient.requireGroupId())
|
||||
|
||||
return if (isGroupTerminated) {
|
||||
DeleteDialog.show(
|
||||
context = context,
|
||||
messageRecords = setOf(record),
|
||||
title = context.getString(R.string.MyStories__delete_story),
|
||||
message = context.getString(R.string.MyStories__delete_story_terminated_group)
|
||||
).map { (_, deletedThread) -> deletedThread }
|
||||
} else {
|
||||
DeleteDialog.show(
|
||||
context = context,
|
||||
messageRecords = setOf(record),
|
||||
title = context.getString(R.string.MyStories__delete_story),
|
||||
message = context.getString(R.string.MyStories__this_story_will_be_deleted),
|
||||
forceRemoteDelete = true
|
||||
).map { (_, deletedThread) -> deletedThread }
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun save(fragment: Fragment, messageRecord: MessageRecord) {
|
||||
|
||||
@@ -327,7 +327,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
|
||||
}
|
||||
|
||||
private fun handleDeleteStory(model: StoriesLandingItem.Model) {
|
||||
lifecycleDisposable += StoryContextMenu.delete(requireContext(), setOf(model.data.primaryStory.messageRecord)).subscribe()
|
||||
lifecycleDisposable += StoryContextMenu.delete(requireContext(), model.data.primaryStory.messageRecord).subscribe()
|
||||
}
|
||||
|
||||
private fun handleHideStory(model: StoriesLandingItem.Model) {
|
||||
|
||||
@@ -161,7 +161,7 @@ class MyStoriesFragment : DSLSettingsFragment(
|
||||
}
|
||||
|
||||
private fun handleDeleteClick(model: MyStoriesItem.Model) {
|
||||
lifecycleDisposable += StoryContextMenu.delete(requireContext(), setOf(model.distributionStory.messageRecord)).subscribe()
|
||||
lifecycleDisposable += StoryContextMenu.delete(requireContext(), model.distributionStory.messageRecord).subscribe()
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
|
||||
@@ -1256,7 +1256,7 @@ class StoryViewerPageFragment :
|
||||
},
|
||||
onDelete = {
|
||||
viewModel.setIsDisplayingDeleteDialog(true)
|
||||
lifecycleDisposable += StoryContextMenu.delete(requireContext(), setOf(it.conversationMessage.messageRecord)).subscribe { _ ->
|
||||
lifecycleDisposable += StoryContextMenu.delete(requireContext(), it.conversationMessage.messageRecord).subscribe { _ ->
|
||||
viewModel.setIsDisplayingDeleteDialog(false)
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
@@ -6894,6 +6894,8 @@
|
||||
<string name="MyStories__delete_story">Delete story?</string>
|
||||
<!-- Message of dialog to confirm deletion of story -->
|
||||
<string name="MyStories__this_story_will_be_deleted">This story will be deleted for you and everyone who received it.</string>
|
||||
<!-- Message of dialog to confirm deletion of story in a terminated group -->
|
||||
<string name="MyStories__delete_story_terminated_group">It will only be deleted for you because the group has ended.</string>
|
||||
<!-- Toast shown when story media cannot be saved -->
|
||||
<string name="MyStories__unable_to_save">Unable to save</string>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user