Prevent UUID-only contacts from being added to GV1 groups.

master
Greyson Parrelli 2020-07-29 23:04:35 -04:00
parent cc84901a49
commit 550b121990
10 changed files with 94 additions and 33 deletions

View File

@ -113,7 +113,9 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) {} public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
return true;
}
@Override @Override
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {} public void onContactDeselected(Optional<RecipientId> recipientId, String number) {}

View File

@ -473,11 +473,15 @@ public final class ContactSelectionListFragment extends LoggingFragment
if (uuid.isPresent()) { if (uuid.isPresent()) {
Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber()); Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber());
SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber()); SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber());
markContactSelected(selected);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
if (onContactSelectedListener != null) { if (onContactSelectedListener != null) {
onContactSelectedListener.onContactSelected(Optional.of(recipient.getId()), null); if (onContactSelectedListener.onContactSelected(Optional.of(recipient.getId()), null)) {
markContactSelected(selected);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
} else {
markContactSelected(selected);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
} }
} else { } else {
new AlertDialog.Builder(requireContext()) new AlertDialog.Builder(requireContext())
@ -488,11 +492,14 @@ public final class ContactSelectionListFragment extends LoggingFragment
} }
}); });
} else { } else {
markContactSelected(selectedContact);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
if (onContactSelectedListener != null) { if (onContactSelectedListener != null) {
onContactSelectedListener.onContactSelected(contact.getRecipientId(), contact.getNumber()); if (onContactSelectedListener.onContactSelected(contact.getRecipientId(), contact.getNumber())) {
markContactSelected(selectedContact);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
} else {
markContactSelected(selectedContact);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
} }
} }
} else { } else {
@ -624,7 +631,8 @@ public final class ContactSelectionListFragment extends LoggingFragment
} }
public interface OnContactSelectedListener { public interface OnContactSelectedListener {
void onContactSelected(Optional<RecipientId> recipientId, String number); /** @return True if the contact is allowed to be selected, otherwise false. */
boolean onContactSelected(Optional<RecipientId> recipientId, String number);
void onContactDeselected(Optional<RecipientId> recipientId, String number); void onContactDeselected(Optional<RecipientId> recipientId, String number);
} }

View File

@ -121,8 +121,9 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) { public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
updateSmsButtonText(); updateSmsButtonText();
return true;
} }
@Override @Override

View File

@ -60,7 +60,7 @@ public class NewConversationActivity extends ContactSelectionActivity
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) { public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
if (recipientId.isPresent()) { if (recipientId.isPresent()) {
launch(Recipient.resolved(recipientId.get())); launch(Recipient.resolved(recipientId.get()));
} else { } else {
@ -92,6 +92,8 @@ public class NewConversationActivity extends ContactSelectionActivity
launch(Recipient.external(this, number)); launch(Recipient.external(this, number));
} }
} }
return true;
} }
private void launch(Recipient recipient) { private void launch(Recipient recipient) {

View File

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.groups.ui.addmembers;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
@ -58,14 +59,19 @@ public class AddMembersActivity extends PushContactSelectionActivity {
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) { public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
if (getGroupId().isV1() && recipientId.isPresent() && !Recipient.resolved(recipientId.get()).hasE164()) {
Toast.makeText(this, R.string.AddMembersActivity__this_person_cant_be_added_to_legacy_groups, Toast.LENGTH_SHORT).show();
return false;
}
if (contactsFragment.hasQueryFilter()) { if (contactsFragment.hasQueryFilter()) {
getToolbar().clear(); getToolbar().clear();
} }
if (contactsFragment.getSelectedContactsCount() >= 1) { enableDone();
enableDone();
} return true;
} }
@Override @Override

View File

@ -39,13 +39,18 @@ public final class AddToGroupViewModel extends ViewModel {
events.postValue(new Event.CloseEvent()); events.postValue(new Event.CloseEvent());
} else if (groupRecipientIds.size() == 1) { } else if (groupRecipientIds.size() == 1) {
SignalExecutors.BOUNDED.execute(() -> { SignalExecutors.BOUNDED.execute(() -> {
Recipient recipient = Recipient.resolved(recipientId);
Recipient groupRecipient = Recipient.resolved(groupRecipientIds.get(0)); Recipient groupRecipient = Recipient.resolved(groupRecipientIds.get(0));
String recipientName = Recipient.resolved(recipientId).getDisplayName(context); String recipientName = recipient.getDisplayName(context);
String groupName = groupRecipient.getDisplayName(context); String groupName = groupRecipient.getDisplayName(context);
events.postValue(new Event.AddToSingleGroupConfirmationEvent(context.getResources().getString(R.string.AddToGroupActivity_add_member), if (groupRecipient.getGroupId().get().isV1() && !recipient.hasE164()) {
context.getResources().getString(R.string.AddToGroupActivity_add_s_to_s, recipientName, groupName), events.postValue(new Event.LegacyGroupDenialEvent());
groupRecipient, recipientName, groupName)); } else {
events.postValue(new Event.AddToSingleGroupConfirmationEvent(context.getResources().getString(R.string.AddToGroupActivity_add_member),
context.getResources().getString(R.string.AddToGroupActivity_add_s_to_s, recipientName, groupName),
groupRecipient, recipientName, groupName));
}
}); });
} else { } else {
throw new AssertionError("Does not support multi-select"); throw new AssertionError("Does not support multi-select");
@ -107,6 +112,9 @@ public final class AddToGroupViewModel extends ViewModel {
return message; return message;
} }
} }
static class LegacyGroupDenialEvent extends Event {
}
} }
public static class Factory implements ViewModelProvider.Factory { public static class Factory implements ViewModelProvider.Factory {

View File

@ -91,6 +91,8 @@ public final class AddToGroupsActivity extends ContactSelectionActivity {
.setPositiveButton(android.R.string.ok, (dialog, which) -> viewModel.onAddToGroupsConfirmed(addEvent)) .setPositiveButton(android.R.string.ok, (dialog, which) -> viewModel.onAddToGroupsConfirmed(addEvent))
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.show(); .show();
} else if (event instanceof Event.LegacyGroupDenialEvent) {
Toast.makeText(this, R.string.AddToGroupActivity_this_person_cant_be_added_to_legacy_groups, Toast.LENGTH_SHORT).show();
} else { } else {
throw new AssertionError(); throw new AssertionError();
} }
@ -112,20 +114,23 @@ public final class AddToGroupsActivity extends ContactSelectionActivity {
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) { public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
if (contactsFragment.isMulti()) { if (contactsFragment.isMulti()) {
if (contactsFragment.hasQueryFilter()) { throw new UnsupportedOperationException("Not yet built to handle multi-select.");
getToolbar().clear(); // if (contactsFragment.hasQueryFilter()) {
} // getToolbar().clear();
// }
if (contactsFragment.getSelectedContactsCount() >= MINIMUM_GROUP_SELECT_SIZE) { //
enableNext(); // if (contactsFragment.getSelectedContactsCount() >= MINIMUM_GROUP_SELECT_SIZE) {
} // enableNext();
// }
} else { } else {
if (recipientId.isPresent()) { if (recipientId.isPresent()) {
viewModel.onContinueWithSelection(Collections.singletonList(recipientId.get())); viewModel.onContinueWithSelection(Collections.singletonList(recipientId.get()));
} }
} }
return true;
} }
@Override @Override

View File

@ -8,6 +8,7 @@ import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
@ -30,6 +31,8 @@ import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
public class CreateGroupActivity extends ContactSelectionActivity { public class CreateGroupActivity extends ContactSelectionActivity {
@ -90,14 +93,14 @@ public class CreateGroupActivity extends ContactSelectionActivity {
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) { public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
if (contactsFragment.hasQueryFilter()) { if (contactsFragment.hasQueryFilter()) {
getToolbar().clear(); getToolbar().clear();
} }
if (contactsFragment.getSelectedContactsCount() >= MINIMUM_GROUP_SIZE) { enableNext();
enableNext();
} return true;
} }
@Override @Override
@ -160,13 +163,31 @@ public class CreateGroupActivity extends ContactSelectionActivity {
stopwatch.split("capabilities"); stopwatch.split("capabilities");
resolved = Recipient.resolvedList(ids);
if (Stream.of(resolved).anyMatch(r -> r.getGroupsV2Capability() != Recipient.Capability.SUPPORTED) &&
Stream.of(resolved).anyMatch(r -> !r.hasE164()))
{
Log.w(TAG, "Invalid GV1 group...");
ids = Collections.emptyList();
}
stopwatch.split("gv1-check");
return ids; return ids;
}, ids -> { }, ids -> {
dismissibleDialog.dismiss(); dismissibleDialog.dismiss();
stopwatch.stop(TAG); stopwatch.stop(TAG);
startActivityForResult(AddGroupDetailsActivity.newIntent(this, ids), REQUEST_CODE_ADD_DETAILS); if (ids.isEmpty()) {
new AlertDialog.Builder(this)
.setMessage(R.string.CreateGroupActivity_some_contacts_cannot_be_in_legacy_groups)
.setPositiveButton(android.R.string.ok, (d, w) -> d.dismiss())
.show();
} else {
startActivityForResult(AddGroupDetailsActivity.newIntent(this, ids), REQUEST_CODE_ADD_DETAILS);
}
}); });
} }
} }

View File

@ -148,8 +148,9 @@ public class ShareActivity extends PassphraseRequiredActivity
else super.onBackPressed(); else super.onBackPressed();
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) { public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
SimpleTask.run(this.getLifecycle(), () -> { SimpleTask.run(this.getLifecycle(), () -> {
Recipient recipient; Recipient recipient;
if (recipientId.isPresent()) { if (recipientId.isPresent()) {
@ -162,6 +163,8 @@ public class ShareActivity extends PassphraseRequiredActivity
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient); long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
return new Pair<>(existingThread, recipient); return new Pair<>(existingThread, recipient);
}, result -> onDestinationChosen(result.first(), result.second().getId())); }, result -> onDestinationChosen(result.first(), result.second().getId()));
return true;
} }
@Override @Override

View File

@ -365,6 +365,9 @@
<string name="ConversationTitleView_verified">Verified</string> <string name="ConversationTitleView_verified">Verified</string>
<string name="ConversationTitleView_you">You</string> <string name="ConversationTitleView_you">You</string>
<!-- CreateGroupActivity -->
<string name="CreateGroupActivity_some_contacts_cannot_be_in_legacy_groups">Some contacts cannot be in legacy groups.</string>
<!-- CreateProfileActivity --> <!-- CreateProfileActivity -->
<string name="CreateProfileActivity__profile">Profile</string> <string name="CreateProfileActivity__profile">Profile</string>
<string name="CreateProfileActivity_error_setting_profile_photo">Error setting profile photo</string> <string name="CreateProfileActivity_error_setting_profile_photo">Error setting profile photo</string>
@ -444,6 +447,7 @@
<string name="AddToGroupActivity_s_added_to_s">\"%1$s\" added to \"%2$s\".</string> <string name="AddToGroupActivity_s_added_to_s">\"%1$s\" added to \"%2$s\".</string>
<string name="AddToGroupActivity_add_to_group">Add to group</string> <string name="AddToGroupActivity_add_to_group">Add to group</string>
<string name="AddToGroupActivity_add_to_groups">Add to groups</string> <string name="AddToGroupActivity_add_to_groups">Add to groups</string>
<string name="AddToGroupActivity_this_person_cant_be_added_to_legacy_groups">This person can\'t be added to legacy groups.</string>
<!-- ChooseNewAdminActivity --> <!-- ChooseNewAdminActivity -->
<string name="ChooseNewAdminActivity_choose_new_admin">Choose new admin</string> <string name="ChooseNewAdminActivity_choose_new_admin">Choose new admin</string>
@ -502,6 +506,7 @@
<!-- AddMembersActivity --> <!-- AddMembersActivity -->
<string name="AddMembersActivity__done">Done</string> <string name="AddMembersActivity__done">Done</string>
<string name="AddMembersActivity__this_person_cant_be_added_to_legacy_groups">This person can\'t be added to legacy groups.</string>
<plurals name="AddMembersActivity__add_d_members_to_s"> <plurals name="AddMembersActivity__add_d_members_to_s">
<item quantity="one">Add \"%1$s\" to \"%2$s\"?</item> <item quantity="one">Add \"%1$s\" to \"%2$s\"?</item>
<item quantity="other">Add %3$d members to \"%2$s\"?</item> <item quantity="other">Add %3$d members to \"%2$s\"?</item>