Show different messages based on join group link error header.

fork-5.53.8
Cody Henthorne 2022-03-11 09:39:20 -05:00
rodzic 5167c7235d
commit c17ba30cfc
11 zmienionych plików z 97 dodań i 22 usunięć

Wyświetl plik

@ -1041,7 +1041,7 @@ final class GroupManagerV2 {
throw new GroupChangeFailedException(e); throw new GroupChangeFailedException(e);
} catch (AuthorizationFailedException e) { } catch (AuthorizationFailedException e) {
Log.w(TAG, e); Log.w(TAG, e);
throw new GroupLinkNotActiveException(e); throw new GroupLinkNotActiveException(e, Optional.absent());
} }
} }

Wyświetl plik

@ -2,5 +2,6 @@ package org.thoughtcrime.securesms.groups.ui.invitesandrequests.joining;
enum FetchGroupDetailsError { enum FetchGroupDetailsError {
GroupLinkNotActive, GroupLinkNotActive,
BannedFromGroup,
NetworkError NetworkError
} }

Wyświetl plik

@ -127,10 +127,7 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
viewModel.isBusy().observe(getViewLifecycleOwner(), isBusy -> busy.setVisibility(isBusy ? View.VISIBLE : View.GONE)); viewModel.isBusy().observe(getViewLifecycleOwner(), isBusy -> busy.setVisibility(isBusy ? View.VISIBLE : View.GONE));
viewModel.getErrors().observe(getViewLifecycleOwner(), error -> { viewModel.getErrors().observe(getViewLifecycleOwner(), this::showError);
Toast.makeText(requireContext(), errorToMessage(error), Toast.LENGTH_SHORT).show();
dismiss();
});
viewModel.getJoinErrors().observe(getViewLifecycleOwner(), error -> Toast.makeText(requireContext(), errorToMessage(error), Toast.LENGTH_SHORT).show()); viewModel.getJoinErrors().observe(getViewLifecycleOwner(), error -> Toast.makeText(requireContext(), errorToMessage(error), Toast.LENGTH_SHORT).show());
@ -156,16 +153,34 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
() -> GroupDescriptionDialog.show(getChildFragmentManager(), name, description, true)); () -> GroupDescriptionDialog.show(getChildFragmentManager(), name, description, true));
} }
private @NonNull String errorToMessage(@NonNull FetchGroupDetailsError error) { private void showError(FetchGroupDetailsError error) {
if (error == FetchGroupDetailsError.GroupLinkNotActive) { avatar.setVisibility(View.INVISIBLE);
return getString(R.string.GroupJoinBottomSheetDialogFragment_this_group_link_is_not_active); groupCancelButton.setVisibility(View.GONE);
groupDetails.setVisibility(View.VISIBLE);
groupJoinButton.setVisibility(View.VISIBLE);
groupJoinButton.setText(getString(android.R.string.ok));
groupJoinButton.setOnClickListener(v -> dismissAllowingStateLoss());
switch (error) {
case GroupLinkNotActive:
groupName.setText(R.string.GroupJoinBottomSheetDialogFragment_cant_join_group);
groupDetails.setText(R.string.GroupJoinBottomSheetDialogFragment_this_group_link_is_no_longer_valid);
break;
case BannedFromGroup:
groupName.setText(R.string.GroupJoinBottomSheetDialogFragment_cant_join_group);
groupDetails.setText(R.string.GroupJoinBottomSheetDialogFragment_you_cant_join_this_group_via_the_group_link_because_an_admin_removed_you);
break;
case NetworkError:
groupName.setText(R.string.GroupJoinBottomSheetDialogFragment_link_error);
groupDetails.setText(R.string.GroupJoinBottomSheetDialogFragment_joining_via_this_link_failed_try_joining_again_later);
break;
} }
return getString(R.string.GroupJoinBottomSheetDialogFragment_unable_to_get_group_information_please_try_again_later);
} }
private @NonNull String errorToMessage(@NonNull JoinGroupError error) { private @NonNull String errorToMessage(@NonNull JoinGroupError error) {
switch (error) { switch (error) {
case GROUP_LINK_NOT_ACTIVE: return getString(R.string.GroupJoinBottomSheetDialogFragment_this_group_link_is_not_active); case GROUP_LINK_NOT_ACTIVE: return getString(R.string.GroupJoinBottomSheetDialogFragment_this_group_link_is_not_active);
case BANNED : return getString(R.string.GroupJoinBottomSheetDialogFragment_you_cant_join_this_group_via_the_group_link_because_an_admin_removed_you);
case NETWORK_ERROR : return getString(R.string.GroupJoinBottomSheetDialogFragment_encountered_a_network_error); case NETWORK_ERROR : return getString(R.string.GroupJoinBottomSheetDialogFragment_encountered_a_network_error);
default : return getString(R.string.GroupJoinBottomSheetDialogFragment_unable_to_join_group_please_try_again_later); default : return getString(R.string.GroupJoinBottomSheetDialogFragment_unable_to_join_group_please_try_again_later);
} }

Wyświetl plik

@ -39,7 +39,9 @@ final class GroupJoinRepository {
callback.onComplete(getGroupDetails()); callback.onComplete(getGroupDetails());
} catch (IOException e) { } catch (IOException e) {
callback.onError(FetchGroupDetailsError.NetworkError); callback.onError(FetchGroupDetailsError.NetworkError);
} catch (VerificationFailedException | GroupLinkNotActiveException e) { } catch (GroupLinkNotActiveException e) {
callback.onError(e.getReason() == GroupLinkNotActiveException.Reason.BANNED ? FetchGroupDetailsError.BannedFromGroup : FetchGroupDetailsError.GroupLinkNotActive);
} catch (VerificationFailedException e) {
callback.onError(FetchGroupDetailsError.GroupLinkNotActive); callback.onError(FetchGroupDetailsError.GroupLinkNotActive);
} }
}); });
@ -62,7 +64,7 @@ final class GroupJoinRepository {
} catch (GroupChangeBusyException e) { } catch (GroupChangeBusyException e) {
callback.onError(JoinGroupError.BUSY); callback.onError(JoinGroupError.BUSY);
} catch (GroupLinkNotActiveException e) { } catch (GroupLinkNotActiveException e) {
callback.onError(JoinGroupError.GROUP_LINK_NOT_ACTIVE); callback.onError(e.getReason() == GroupLinkNotActiveException.Reason.BANNED ? JoinGroupError.BANNED : JoinGroupError.GROUP_LINK_NOT_ACTIVE);
} catch (GroupChangeFailedException | MembershipNotSuitableForV2Exception e) { } catch (GroupChangeFailedException | MembershipNotSuitableForV2Exception e) {
callback.onError(JoinGroupError.FAILED); callback.onError(JoinGroupError.FAILED);
} }

Wyświetl plik

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.groups.ui.invitesandrequests.joining;
enum JoinGroupError { enum JoinGroupError {
BUSY, BUSY,
GROUP_LINK_NOT_ACTIVE, GROUP_LINK_NOT_ACTIVE,
BANNED,
FAILED, FAILED,
NETWORK_ERROR, NETWORK_ERROR,
} }

Wyświetl plik

@ -44,8 +44,11 @@
<TextView <TextView
android:id="@+id/group_join_group_details" android:id="@+id/group_join_group_details"
style="@style/Signal.Text.Body" style="@style/Signal.Text.Body"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:gravity="center_horizontal"
android:textColor="@color/signal_text_secondary" android:textColor="@color/signal_text_secondary"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
@ -95,7 +98,6 @@
android:layout_height="64dp" android:layout_height="64dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:text="@android:string/cancel" android:text="@android:string/cancel"
android:visibility="invisible" android:visibility="invisible"
@ -112,7 +114,7 @@
style="@style/Button.Primary" style="@style/Button.Primary"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="64dp" android:layout_height="64dp"
android:layout_marginStart="0dp" android:layout_marginStart="16dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"

Wyświetl plik

@ -873,8 +873,17 @@
<string name="GroupJoinBottomSheetDialogFragment_unable_to_join_group_please_try_again_later">Unable to join group. Please try again later</string> <string name="GroupJoinBottomSheetDialogFragment_unable_to_join_group_please_try_again_later">Unable to join group. Please try again later</string>
<string name="GroupJoinBottomSheetDialogFragment_encountered_a_network_error">Encountered a network error.</string> <string name="GroupJoinBottomSheetDialogFragment_encountered_a_network_error">Encountered a network error.</string>
<string name="GroupJoinBottomSheetDialogFragment_this_group_link_is_not_active">This group link is not active</string> <string name="GroupJoinBottomSheetDialogFragment_this_group_link_is_not_active">This group link is not active</string>
<!-- Title shown when there was an known issue getting group information from a group link -->
<string name="GroupJoinBottomSheetDialogFragment_cant_join_group">Can\'t join group</string>
<!-- Message shown when you try to get information for a group via link but an admin has removed you -->
<string name="GroupJoinBottomSheetDialogFragment_you_cant_join_this_group_via_the_group_link_because_an_admin_removed_you">You can\'t join this group via the group link because an admin removed you.</string>
<!-- Message shown when you try to get information for a group via link but the link is no longer valid -->
<string name="GroupJoinBottomSheetDialogFragment_this_group_link_is_no_longer_valid">This group link is no longer valid.</string>
<!-- Title shown when there was an unknown issue getting group information from a group link -->
<string name="GroupJoinBottomSheetDialogFragment_link_error">Link error</string>
<!-- Message shown when you try to get information for a group via link but an unknown issue occurred -->
<string name="GroupJoinBottomSheetDialogFragment_joining_via_this_link_failed_try_joining_again_later">Joining via this link failed. Try joining again later.</string>
<string name="GroupJoinBottomSheetDialogFragment_unable_to_get_group_information_please_try_again_later">Unable to get group information, please try again later</string>
<string name="GroupJoinBottomSheetDialogFragment_direct_join">Do you want to join this group and share your name and photo with its members?</string> <string name="GroupJoinBottomSheetDialogFragment_direct_join">Do you want to join this group and share your name and photo with its members?</string>
<string name="GroupJoinBottomSheetDialogFragment_admin_approval_needed">An admin of this group must approve your request before you can join this group. When you request to join, your name and photo will be shared with its members.</string> <string name="GroupJoinBottomSheetDialogFragment_admin_approval_needed">An admin of this group must approve your request before you can join this group. When you request to join, your name and photo will be shared with its members.</string>
<plurals name="GroupJoinBottomSheetDialogFragment_group_dot_d_members"> <plurals name="GroupJoinBottomSheetDialogFragment_group_dot_d_members">

Wyświetl plik

@ -1,16 +1,34 @@
package org.whispersystems.signalservice.api.groupsv2; package org.whispersystems.signalservice.api.groupsv2;
import org.whispersystems.libsignal.util.guava.Optional;
/** /**
* Thrown when a group link: * Thrown when a group link:
* - has an out of date password, or; * - has an out of date password, or;
* - is currently not shared, or; * - is currently not shared, or;
* - has been banned from the group, or;
* - the master key does not match a group on the server * - the master key does not match a group on the server
*/ */
public final class GroupLinkNotActiveException extends Exception { public final class GroupLinkNotActiveException extends Exception {
public GroupLinkNotActiveException() {
private final Reason reason;
public GroupLinkNotActiveException(Throwable t, Optional<String> reason) {
super(t);
if (reason.isPresent() && reason.get().equalsIgnoreCase("banned")) {
this.reason = Reason.BANNED;
} else {
this.reason = Reason.UNKNOWN;
}
} }
public GroupLinkNotActiveException(Throwable t) { public Reason getReason() {
super(t); return reason;
}
public enum Reason {
UNKNOWN,
BANNED
} }
} }

Wyświetl plik

@ -134,7 +134,7 @@ public class GroupsV2Api {
return groupOperations.decryptGroupJoinInfo(joinInfo); return groupOperations.decryptGroupJoinInfo(joinInfo);
} catch (ForbiddenException e) { } catch (ForbiddenException e) {
throw new GroupLinkNotActiveException(); throw new GroupLinkNotActiveException(null, e.getReason());
} }
} }

Wyświetl plik

@ -36,6 +36,7 @@ import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Function;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.account.AccountAttributes; import org.whispersystems.signalservice.api.account.AccountAttributes;
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest; import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest;
@ -1968,7 +1969,7 @@ public class PushServiceSocket {
ResponseBody responseBody = response.body(); ResponseBody responseBody = response.body();
try { try {
responseCodeHandler.handle(response.code(), responseBody); responseCodeHandler.handle(response.code(), responseBody, response::header);
switch (response.code()) { switch (response.code()) {
case 204: case 204:
@ -2293,6 +2294,10 @@ public class PushServiceSocket {
private interface ResponseCodeHandler { private interface ResponseCodeHandler {
void handle(int responseCode, ResponseBody body) throws NonSuccessfulResponseCodeException, PushNetworkException; void handle(int responseCode, ResponseBody body) throws NonSuccessfulResponseCodeException, PushNetworkException;
default void handle(int responseCode, ResponseBody body, Function<String, String> getHeader) throws NonSuccessfulResponseCodeException, PushNetworkException {
handle(responseCode, body);
}
} }
private static class EmptyResponseCodeHandler implements ResponseCodeHandler { private static class EmptyResponseCodeHandler implements ResponseCodeHandler {
@ -2328,8 +2333,18 @@ public class PushServiceSocket {
private static final ResponseCodeHandler GROUPS_V2_PATCH_RESPONSE_HANDLER = (responseCode, body) -> { private static final ResponseCodeHandler GROUPS_V2_PATCH_RESPONSE_HANDLER = (responseCode, body) -> {
if (responseCode == 400) throw new GroupPatchNotAcceptedException(); if (responseCode == 400) throw new GroupPatchNotAcceptedException();
}; };
private static final ResponseCodeHandler GROUPS_V2_GET_JOIN_INFO_HANDLER = (responseCode, body) -> { private static final ResponseCodeHandler GROUPS_V2_GET_JOIN_INFO_HANDLER = new ResponseCodeHandler() {
if (responseCode == 403) throw new ForbiddenException(); @Override
public void handle(int responseCode, ResponseBody body) throws NonSuccessfulResponseCodeException {
if (responseCode == 403) throw new ForbiddenException();
}
@Override
public void handle(int responseCode, ResponseBody body, Function<String, String> getHeader) throws NonSuccessfulResponseCodeException {
if (responseCode == 403) {
throw new ForbiddenException(Optional.fromNullable(getHeader.apply("X-Signal-Forbidden-Reason")));
}
}
}; };
public void putNewGroupsV2Group(Group group, GroupsV2AuthorizationString authorization) public void putNewGroupsV2Group(Group group, GroupsV2AuthorizationString authorization)

Wyświetl plik

@ -1,9 +1,21 @@
package org.whispersystems.signalservice.internal.push.exceptions; package org.whispersystems.signalservice.internal.push.exceptions;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
public final class ForbiddenException extends NonSuccessfulResponseCodeException { public final class ForbiddenException extends NonSuccessfulResponseCodeException {
private Optional<String> reason;
public ForbiddenException() { public ForbiddenException() {
this(Optional.absent());
}
public ForbiddenException(Optional<String> reason) {
super(403); super(403);
this.reason = reason;
}
public Optional<String> getReason() {
return reason;
} }
} }