mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Support requesting a CAPTCHA during registration.
This commit is contained in:
parent
2cfa431cad
commit
02b0800b22
@ -305,6 +305,12 @@
|
||||
android:windowSoftInputMode="stateUnchanged"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".registration.CaptchaActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/TextSecure.LightNoActionBar"
|
||||
android:windowSoftInputMode="stateUnchanged"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".DeviceActivity"
|
||||
android:label="@string/AndroidManifest__linked_devices"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
41
res/layout/captcha_activity.xml
Normal file
41
res/layout/captcha_activity.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/registration_captcha_title"
|
||||
style="@style/Signal.Text.Headline"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginRight="24dp"
|
||||
android:text="@string/RegistrationActivity_we_need_to_verify_that_youre_human"
|
||||
android:gravity="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<WebView
|
||||
android:id="@+id/registration_captcha_web_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/registration_captcha_title" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
@ -597,6 +597,8 @@
|
||||
<item quantity="one">You are now %d step away from submitting a debug log.</item>
|
||||
<item quantity="other">You are now %d steps away from submitting a debug log.</item>
|
||||
</plurals>
|
||||
<string name="RegistrationActivity_we_need_to_verify_that_youre_human">We need to verify that you\'re human.</string>
|
||||
<string name="RegistrationActivity_failed_to_verify_the_captcha">Failed to verify the CAPTCHA</string>
|
||||
|
||||
<!-- ScribbleActivity -->
|
||||
<string name="ScribbleActivity_save_failure">Failed to save image changes</string>
|
||||
|
@ -78,6 +78,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
||||
import org.thoughtcrime.securesms.registration.CaptchaActivity;
|
||||
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||
import org.thoughtcrime.securesms.service.VerificationCodeParser;
|
||||
@ -96,6 +97,7 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
import org.whispersystems.libsignal.util.KeyHelper;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.RateLimitException;
|
||||
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
|
||||
import org.whispersystems.signalservice.internal.push.LockedException;
|
||||
@ -117,6 +119,7 @@ import java.util.concurrent.TimeUnit;
|
||||
public class RegistrationActivity extends BaseActionBarActivity implements VerificationCodeView.OnCodeEnteredListener {
|
||||
|
||||
private static final int PICK_COUNTRY = 1;
|
||||
private static final int CAPTCHA = 24601;
|
||||
private static final int SCENE_TRANSITION_DURATION = 250;
|
||||
private static final int DEBUG_TAP_TARGET = 8;
|
||||
private static final int DEBUG_TAP_ANNOUNCE = 4;
|
||||
@ -185,6 +188,16 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
this.countryCode.setText(String.valueOf(data.getIntExtra("country_code", 1)));
|
||||
setCountryDisplay(data.getStringExtra("country_name"));
|
||||
setCountryFormatter(data.getIntExtra("country_code", 1));
|
||||
} else if (requestCode == CAPTCHA && resultCode == RESULT_OK && data != null) {
|
||||
registrationState = new RegistrationState(Optional.fromNullable(data.getStringExtra(CaptchaActivity.KEY_TOKEN)), registrationState);
|
||||
|
||||
if (data.getBooleanExtra(CaptchaActivity.KEY_IS_SMS, true)) {
|
||||
handleRegister();
|
||||
} else {
|
||||
handlePhoneCallRequest();
|
||||
}
|
||||
} else if (requestCode == CAPTCHA) {
|
||||
Toast.makeText(this, R.string.RegistrationActivity_failed_to_verify_the_captcha, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,7 +239,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
this.pinForgotButton = findViewById(R.id.forgot_button);
|
||||
this.pinClarificationContainer = findViewById(R.id.pin_clarification_container);
|
||||
|
||||
this.registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, null);
|
||||
this.registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
|
||||
|
||||
this.countryCode.addTextChangedListener(new CountryCodeChangedListener());
|
||||
this.number.addTextChangedListener(new NumberChangedListener());
|
||||
@ -388,13 +401,14 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
restoreButton.setIndeterminateProgressMode(true);
|
||||
restoreButton.setProgress(50);
|
||||
|
||||
final String passphrase = prompt.getText().toString();
|
||||
|
||||
new AsyncTask<Void, Void, BackupImportResult>() {
|
||||
@Override
|
||||
protected BackupImportResult doInBackground(Void... voids) {
|
||||
try {
|
||||
Context context = RegistrationActivity.this;
|
||||
String passphrase = prompt.getText().toString();
|
||||
SQLiteDatabase database = DatabaseFactory.getBackupDatabase(context);
|
||||
Context context = RegistrationActivity.this;
|
||||
SQLiteDatabase database = DatabaseFactory.getBackupDatabase(context);
|
||||
|
||||
FullBackupImporter.importFile(context,
|
||||
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
||||
@ -498,9 +512,9 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private void requestVerificationCode(@NonNull String e164number, boolean gcmSupported, boolean smsRetrieverSupported) {
|
||||
new AsyncTask<Void, Void, Pair<String, Optional<String>>> () {
|
||||
new AsyncTask<Void, Void, VerificationRequestResult> () {
|
||||
@Override
|
||||
protected @Nullable Pair<String, Optional<String>> doInBackground(Void... voids) {
|
||||
protected @NonNull VerificationRequestResult doInBackground(Void... voids) {
|
||||
try {
|
||||
markAsVerifying(true);
|
||||
|
||||
@ -515,29 +529,34 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
}
|
||||
|
||||
accountManager = AccountManagerFactory.createManager(RegistrationActivity.this, e164number, password);
|
||||
accountManager.requestSmsVerificationCode(smsRetrieverSupported);
|
||||
accountManager.requestSmsVerificationCode(smsRetrieverSupported, registrationState.captchaToken);
|
||||
|
||||
return new Pair<>(password, fcmToken);
|
||||
return new VerificationRequestResult(password, fcmToken, Optional.absent());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Error during account registration", e);
|
||||
return null;
|
||||
return new VerificationRequestResult(null, Optional.absent(), Optional.of(e));
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(@Nullable Pair<String, Optional<String>> result) {
|
||||
if (result == null) {
|
||||
protected void onPostExecute(@NonNull VerificationRequestResult result) {
|
||||
if (result.exception.isPresent() && result.exception.get() instanceof CaptchaRequiredException) {
|
||||
requestCaptcha(true);
|
||||
} else if (result.exception.isPresent()) {
|
||||
Toast.makeText(RegistrationActivity.this, R.string.RegistrationActivity_unable_to_connect_to_service, Toast.LENGTH_LONG).show();
|
||||
createButton.setIndeterminateProgressMode(false);
|
||||
createButton.setProgress(0);
|
||||
return;
|
||||
} else {
|
||||
registrationState = new RegistrationState(RegistrationState.State.VERIFYING, e164number, result.password, result.fcmToken, Optional.absent());
|
||||
displayVerificationView(e164number, 64);
|
||||
}
|
||||
|
||||
registrationState = new RegistrationState(RegistrationState.State.VERIFYING, e164number, result.first, result.second);
|
||||
displayVerificationView(e164number, 64);
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void requestCaptcha(boolean isSms) {
|
||||
startActivityForResult(CaptchaActivity.getIntent(this, isSms), CAPTCHA);
|
||||
}
|
||||
|
||||
private void handleVerificationCodeReceived(@Nullable String code) {
|
||||
List<Integer> parsedCode = convertVerificationCodeToDigits(code);
|
||||
|
||||
@ -693,7 +712,9 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
try {
|
||||
accountManager.requestVoiceVerificationCode(Locale.getDefault());
|
||||
accountManager.requestVoiceVerificationCode(Locale.getDefault(), registrationState.captchaToken);
|
||||
} catch (CaptchaRequiredException e) {
|
||||
requestCaptcha(false);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@ -892,7 +913,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
@Override
|
||||
public void onClick(View widget) {
|
||||
displayInitialView(false);
|
||||
registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, null);
|
||||
registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1157,28 +1178,51 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
||||
}
|
||||
}
|
||||
|
||||
private static class VerificationRequestResult {
|
||||
private final String password;
|
||||
private final Optional<String> fcmToken;
|
||||
private final Optional<IOException> exception;
|
||||
|
||||
private VerificationRequestResult(String password, Optional<String> fcmToken, Optional<IOException> exception) {
|
||||
this.password = password;
|
||||
this.fcmToken = fcmToken;
|
||||
this.exception = exception;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegistrationState {
|
||||
private enum State {
|
||||
INITIAL, VERIFYING, CHECKING, PIN
|
||||
}
|
||||
|
||||
private final State state;
|
||||
private final String e164number;
|
||||
private final String password;
|
||||
private final State state;
|
||||
private final String e164number;
|
||||
private final String password;
|
||||
private final Optional<String> gcmToken;
|
||||
private final Optional<String> captchaToken;
|
||||
|
||||
RegistrationState(State state, String e164number, String password, Optional<String> gcmToken) {
|
||||
this.state = state;
|
||||
this.e164number = e164number;
|
||||
this.password = password;
|
||||
this.gcmToken = gcmToken;
|
||||
RegistrationState(State state, String e164number, String password, Optional<String> gcmToken, Optional<String> captchaToken) {
|
||||
this.state = state;
|
||||
this.e164number = e164number;
|
||||
this.password = password;
|
||||
this.gcmToken = gcmToken;
|
||||
this.captchaToken = captchaToken;
|
||||
}
|
||||
|
||||
RegistrationState(State state, RegistrationState previous) {
|
||||
this.state = state;
|
||||
this.e164number = previous.e164number;
|
||||
this.password = previous.password;
|
||||
this.gcmToken = previous.gcmToken;
|
||||
this.state = state;
|
||||
this.e164number = previous.e164number;
|
||||
this.password = previous.password;
|
||||
this.gcmToken = previous.gcmToken;
|
||||
this.captchaToken = previous.captchaToken;
|
||||
}
|
||||
|
||||
RegistrationState(Optional<String> captchaToken, RegistrationState previous) {
|
||||
this.state = previous.state;
|
||||
this.e164number = previous.e164number;
|
||||
this.password = previous.password;
|
||||
this.gcmToken = previous.gcmToken;
|
||||
this.captchaToken = captchaToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
package org.thoughtcrime.securesms.registration;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class CaptchaActivity extends BaseActionBarActivity {
|
||||
|
||||
public static final String KEY_TOKEN = "token";
|
||||
public static final String KEY_IS_SMS = "is_sms";
|
||||
|
||||
private static final String SIGNAL_SCHEME = "signalcaptcha://";
|
||||
|
||||
public static Intent getIntent(@NonNull Context context, boolean isSms) {
|
||||
Intent intent = new Intent(context, CaptchaActivity.class);
|
||||
intent.putExtra(KEY_IS_SMS, isSms);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.captcha_activity);
|
||||
|
||||
WebView webView = findViewById(R.id.registration_captcha_web_view);
|
||||
|
||||
webView.getSettings().setJavaScriptEnabled(true);
|
||||
webView.clearCache(true);
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (url != null && url.startsWith(SIGNAL_SCHEME)) {
|
||||
handleToken(url.substring(SIGNAL_SCHEME.length()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
webView.loadUrl("https://signalcaptchas.org/registration/generate.html\n");
|
||||
}
|
||||
|
||||
public void handleToken(String token) {
|
||||
if (!TextUtils.isEmpty(token)) {
|
||||
Intent result = new Intent();
|
||||
result.putExtra(KEY_TOKEN, token);
|
||||
result.putExtra(KEY_IS_SMS, getIntent().getBooleanExtra(KEY_IS_SMS, true));
|
||||
setResult(RESULT_OK, result);
|
||||
} else {
|
||||
setResult(RESULT_CANCELED);
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user