mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 16:08:33 +00:00
Request a push challenge and supply to SMS and voice verification.
This commit is contained in:
parent
d72d4c4c41
commit
5b61c8ac18
@ -9,9 +9,6 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
@ -28,6 +25,10 @@ import android.widget.Spinner;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import com.dd.CircularProgressButton;
|
import com.dd.CircularProgressButton;
|
||||||
import com.google.android.gms.auth.api.phone.SmsRetriever;
|
import com.google.android.gms.auth.api.phone.SmsRetriever;
|
||||||
import com.google.android.gms.auth.api.phone.SmsRetrieverClient;
|
import com.google.android.gms.auth.api.phone.SmsRetrieverClient;
|
||||||
@ -71,6 +72,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
|||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||||
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
||||||
import org.thoughtcrime.securesms.registration.CaptchaActivity;
|
import org.thoughtcrime.securesms.registration.CaptchaActivity;
|
||||||
|
import org.thoughtcrime.securesms.registration.PushChallengeRequest;
|
||||||
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
||||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||||
import org.thoughtcrime.securesms.service.VerificationCodeParser;
|
import org.thoughtcrime.securesms.service.VerificationCodeParser;
|
||||||
@ -115,7 +117,9 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
private static final int SCENE_TRANSITION_DURATION = 250;
|
private static final int SCENE_TRANSITION_DURATION = 250;
|
||||||
private static final int DEBUG_TAP_TARGET = 8;
|
private static final int DEBUG_TAP_TARGET = 8;
|
||||||
private static final int DEBUG_TAP_ANNOUNCE = 4;
|
private static final int DEBUG_TAP_ANNOUNCE = 4;
|
||||||
public static final String RE_REGISTRATION_EXTRA = "re_registration";
|
private static final long PUSH_REQUEST_TIMEOUT_MS = 5000L;
|
||||||
|
|
||||||
|
public static final String RE_REGISTRATION_EXTRA = "re_registration";
|
||||||
|
|
||||||
private static final String TAG = RegistrationActivity.class.getSimpleName();
|
private static final String TAG = RegistrationActivity.class.getSimpleName();
|
||||||
|
|
||||||
@ -492,7 +496,10 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
}
|
}
|
||||||
|
|
||||||
accountManager = AccountManagerFactory.createManager(RegistrationActivity.this, e164number, password);
|
accountManager = AccountManagerFactory.createManager(RegistrationActivity.this, e164number, password);
|
||||||
accountManager.requestSmsVerificationCode(smsRetrieverSupported, registrationState.captchaToken, Optional.absent());
|
|
||||||
|
Optional<String> pushChallenge = PushChallengeRequest.getPushChallengeBlocking(accountManager, fcmToken, e164number, PUSH_REQUEST_TIMEOUT_MS);
|
||||||
|
|
||||||
|
accountManager.requestSmsVerificationCode(smsRetrieverSupported, registrationState.captchaToken, pushChallenge);
|
||||||
|
|
||||||
return new VerificationRequestResult(password, fcmToken, Optional.absent());
|
return new VerificationRequestResult(password, fcmToken, Optional.absent());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -668,6 +675,8 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private void handlePhoneCallRequest() {
|
private void handlePhoneCallRequest() {
|
||||||
|
final String e164number = getConfiguredE164Number();
|
||||||
|
|
||||||
if (registrationState.state == RegistrationState.State.VERIFYING) {
|
if (registrationState.state == RegistrationState.State.VERIFYING) {
|
||||||
callMeCountDownView.startCountDown(300);
|
callMeCountDownView.startCountDown(300);
|
||||||
|
|
||||||
@ -675,7 +684,9 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
accountManager.requestVoiceVerificationCode(Locale.getDefault(), registrationState.captchaToken, Optional.absent());
|
Optional<String> pushChallenge = PushChallengeRequest.getPushChallengeBlocking(accountManager, getFcmToken(), e164number, PUSH_REQUEST_TIMEOUT_MS);
|
||||||
|
|
||||||
|
accountManager.requestVoiceVerificationCode(Locale.getDefault(), registrationState.captchaToken, pushChallenge);
|
||||||
} catch (CaptchaRequiredException e) {
|
} catch (CaptchaRequiredException e) {
|
||||||
requestCaptcha(false);
|
requestCaptcha(false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -688,6 +699,15 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<String> getFcmToken() {
|
||||||
|
final boolean gcmSupported = PlayServicesUtil.getPlayServicesStatus(this) == PlayServicesStatus.SUCCESS;
|
||||||
|
if (gcmSupported) {
|
||||||
|
return FcmUtil.getToken();
|
||||||
|
} else {
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyAccount(@NonNull String code, @Nullable String pin) throws IOException {
|
private void verifyAccount(@NonNull String code, @Nullable String pin) throws IOException {
|
||||||
int registrationId = KeyHelper.generateRegistrationId(false);
|
int registrationId = KeyHelper.generateRegistrationId(false);
|
||||||
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(RegistrationActivity.this);
|
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(RegistrationActivity.this);
|
||||||
|
@ -4,6 +4,8 @@ import android.content.Context;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||||
import com.google.firebase.messaging.RemoteMessage;
|
import com.google.firebase.messaging.RemoteMessage;
|
||||||
|
|
||||||
@ -13,6 +15,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|||||||
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
|
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
|
||||||
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.registration.PushChallengeRequest;
|
||||||
import org.thoughtcrime.securesms.util.PowerManagerCompat;
|
import org.thoughtcrime.securesms.util.PowerManagerCompat;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
@ -38,11 +41,17 @@ public class FcmService extends FirebaseMessagingService implements InjectableTy
|
|||||||
@Override
|
@Override
|
||||||
public void onMessageReceived(RemoteMessage remoteMessage) {
|
public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||||
Log.i(TAG, "FCM message... Original Priority: " + remoteMessage.getOriginalPriority() + ", Actual Priority: " + remoteMessage.getPriority());
|
Log.i(TAG, "FCM message... Original Priority: " + remoteMessage.getOriginalPriority() + ", Actual Priority: " + remoteMessage.getPriority());
|
||||||
ApplicationContext.getInstance(getApplicationContext()).injectDependencies(this);
|
|
||||||
|
|
||||||
WakeLockUtil.runWithLock(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK, 60000, WAKE_LOCK_TAG, () -> {
|
String challenge = remoteMessage.getData().get("challenge");
|
||||||
handleReceivedNotification(getApplicationContext());
|
if (challenge != null) {
|
||||||
});
|
handlePushChallenge(challenge);
|
||||||
|
} else {
|
||||||
|
ApplicationContext.getInstance(getApplicationContext()).injectDependencies(this);
|
||||||
|
|
||||||
|
WakeLockUtil.runWithLock(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK, 60000, WAKE_LOCK_TAG, () ->
|
||||||
|
handleReceivedNotification(getApplicationContext())
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -95,6 +104,12 @@ public class FcmService extends FirebaseMessagingService implements InjectableTy
|
|||||||
Log.i(TAG, "Processing complete.");
|
Log.i(TAG, "Processing complete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void handlePushChallenge(@NonNull String challenge) {
|
||||||
|
Log.d(TAG, String.format("Got a push challenge \"%s\"", challenge));
|
||||||
|
|
||||||
|
PushChallengeRequest.postChallengeResponse(challenge);
|
||||||
|
}
|
||||||
|
|
||||||
private static synchronized boolean incrementActiveGcmCount() {
|
private static synchronized boolean incrementActiveGcmCount() {
|
||||||
if (activeCount < 2) {
|
if (activeCount < 2) {
|
||||||
activeCount++;
|
activeCount++;
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
package org.thoughtcrime.securesms.registration;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
public final class PushChallengeRequest {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(PushChallengeRequest.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a push challenge and waits for the response.
|
||||||
|
* <p>
|
||||||
|
* Blocks the current thread for up to {@param timeoutMs} milliseconds.
|
||||||
|
*
|
||||||
|
* @param accountManager Account manager to request the push from.
|
||||||
|
* @param fcmToken Optional FCM token. If not present will return absent.
|
||||||
|
* @param e164number Local number.
|
||||||
|
* @param timeoutMs Timeout in milliseconds
|
||||||
|
* @return Either returns a challenge, or absent.
|
||||||
|
*/
|
||||||
|
@WorkerThread
|
||||||
|
public static Optional<String> getPushChallengeBlocking(@NonNull SignalServiceAccountManager accountManager,
|
||||||
|
@NonNull Optional<String> fcmToken,
|
||||||
|
@NonNull String e164number,
|
||||||
|
long timeoutMs)
|
||||||
|
{
|
||||||
|
if (!fcmToken.isPresent()) {
|
||||||
|
Log.w(TAG, "Push challenge not requested, as no FCM token was present");
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
Log.i(TAG, "Requesting a push challenge");
|
||||||
|
|
||||||
|
Request request = new Request(accountManager, fcmToken.get(), e164number, timeoutMs);
|
||||||
|
|
||||||
|
Optional<String> challenge = request.requestAndReceiveChallengeBlocking();
|
||||||
|
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
|
||||||
|
if (challenge.isPresent()) {
|
||||||
|
Log.i(TAG, String.format(Locale.US, "Received a push challenge \"%s\" in %d ms", challenge.get(), duration));
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, String.format(Locale.US, "Did not received a push challenge in %d ms", duration));
|
||||||
|
}
|
||||||
|
return challenge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void postChallengeResponse(@NonNull String challenge) {
|
||||||
|
EventBus.getDefault().post(new PushChallengeEvent(challenge));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Request {
|
||||||
|
|
||||||
|
private final CountDownLatch latch;
|
||||||
|
private final AtomicReference<String> challenge;
|
||||||
|
private final SignalServiceAccountManager accountManager;
|
||||||
|
private final String fcmToken;
|
||||||
|
private final String e164number;
|
||||||
|
private final long timeoutMs;
|
||||||
|
|
||||||
|
private Request(@NonNull SignalServiceAccountManager accountManager,
|
||||||
|
@NonNull String fcmToken,
|
||||||
|
@NonNull String e164number,
|
||||||
|
long timeoutMs)
|
||||||
|
{
|
||||||
|
this.latch = new CountDownLatch(1);
|
||||||
|
this.challenge = new AtomicReference<>();
|
||||||
|
this.accountManager = accountManager;
|
||||||
|
this.fcmToken = fcmToken;
|
||||||
|
this.e164number = e164number;
|
||||||
|
this.timeoutMs = timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private Optional<String> requestAndReceiveChallengeBlocking() {
|
||||||
|
EventBus eventBus = EventBus.getDefault();
|
||||||
|
|
||||||
|
eventBus.register(this);
|
||||||
|
try {
|
||||||
|
accountManager.requestPushChallenge(fcmToken, e164number);
|
||||||
|
|
||||||
|
latch.await(timeoutMs, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
return Optional.fromNullable(challenge.get());
|
||||||
|
} catch (InterruptedException | IOException e) {
|
||||||
|
Log.w(TAG, "Error getting push challenge", e);
|
||||||
|
return Optional.absent();
|
||||||
|
} finally {
|
||||||
|
eventBus.unregister(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.POSTING)
|
||||||
|
public void onChallengeEvent(@NonNull PushChallengeEvent pushChallengeEvent) {
|
||||||
|
challenge.set(pushChallengeEvent.challenge);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PushChallengeEvent {
|
||||||
|
private final String challenge;
|
||||||
|
|
||||||
|
PushChallengeEvent(String challenge) {
|
||||||
|
this.challenge = challenge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
package org.thoughtcrime.securesms.registration;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||||
|
import static org.hamcrest.Matchers.lessThan;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(manifest = Config.NONE, application = Application.class)
|
||||||
|
public final class PushChallengeRequestTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPushChallengeBlocking_returns_absent_if_times_out() {
|
||||||
|
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||||
|
|
||||||
|
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 50L);
|
||||||
|
|
||||||
|
assertFalse(challenge.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPushChallengeBlocking_waits_for_specified_period() {
|
||||||
|
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 250L);
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
|
||||||
|
assertThat(duration, greaterThanOrEqualTo(250L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPushChallengeBlocking_completes_fast_if_posted_to_event_bus() throws IOException {
|
||||||
|
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
AsyncTask.execute(() -> PushChallengeRequest.postChallengeResponse("CHALLENGE"));
|
||||||
|
return null;
|
||||||
|
}).when(signal).requestPushChallenge("token", "+123456");
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 500L);
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
|
||||||
|
assertThat(duration, lessThan(500L));
|
||||||
|
verify(signal).requestPushChallenge("token", "+123456");
|
||||||
|
verifyNoMoreInteractions(signal);
|
||||||
|
|
||||||
|
assertTrue(challenge.isPresent());
|
||||||
|
assertEquals("CHALLENGE", challenge.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPushChallengeBlocking_returns_fast_if_no_fcm_token_supplied() {
|
||||||
|
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
PushChallengeRequest.getPushChallengeBlocking(signal, Optional.absent(), "+123456", 500L);
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
|
||||||
|
assertThat(duration, lessThan(500L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPushChallengeBlocking_returns_absent_if_no_fcm_token_supplied() {
|
||||||
|
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||||
|
|
||||||
|
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.absent(), "+123456", 500L);
|
||||||
|
|
||||||
|
verifyZeroInteractions(signal);
|
||||||
|
assertFalse(challenge.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPushChallengeBlocking_returns_absent_if_any_IOException_is_thrown() throws IOException {
|
||||||
|
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||||
|
|
||||||
|
doThrow(new IOException()).when(signal).requestPushChallenge(any(), any());
|
||||||
|
|
||||||
|
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 500L);
|
||||||
|
|
||||||
|
assertFalse(challenge.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPushChallengeBlocking_returns_absent_if_any_RuntimeException_is_thrown() throws IOException {
|
||||||
|
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||||
|
|
||||||
|
doThrow(new RuntimeException()).when(signal).requestPushChallenge(any(), any());
|
||||||
|
|
||||||
|
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 500L);
|
||||||
|
|
||||||
|
assertFalse(challenge.isPresent());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user