mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-02 14:35:21 +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:windowSoftInputMode="stateUnchanged"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
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"
|
<activity android:name=".DeviceActivity"
|
||||||
android:label="@string/AndroidManifest__linked_devices"
|
android:label="@string/AndroidManifest__linked_devices"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
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="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>
|
<item quantity="other">You are now %d steps away from submitting a debug log.</item>
|
||||||
</plurals>
|
</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 -->
|
<!-- ScribbleActivity -->
|
||||||
<string name="ScribbleActivity_save_failure">Failed to save image changes</string>
|
<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.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.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;
|
||||||
@ -96,6 +97,7 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
|||||||
import org.whispersystems.libsignal.util.KeyHelper;
|
import org.whispersystems.libsignal.util.KeyHelper;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
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.push.exceptions.RateLimitException;
|
||||||
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
|
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
|
||||||
import org.whispersystems.signalservice.internal.push.LockedException;
|
import org.whispersystems.signalservice.internal.push.LockedException;
|
||||||
@ -117,6 +119,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class RegistrationActivity extends BaseActionBarActivity implements VerificationCodeView.OnCodeEnteredListener {
|
public class RegistrationActivity extends BaseActionBarActivity implements VerificationCodeView.OnCodeEnteredListener {
|
||||||
|
|
||||||
private static final int PICK_COUNTRY = 1;
|
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 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;
|
||||||
@ -185,6 +188,16 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
this.countryCode.setText(String.valueOf(data.getIntExtra("country_code", 1)));
|
this.countryCode.setText(String.valueOf(data.getIntExtra("country_code", 1)));
|
||||||
setCountryDisplay(data.getStringExtra("country_name"));
|
setCountryDisplay(data.getStringExtra("country_name"));
|
||||||
setCountryFormatter(data.getIntExtra("country_code", 1));
|
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.pinForgotButton = findViewById(R.id.forgot_button);
|
||||||
this.pinClarificationContainer = findViewById(R.id.pin_clarification_container);
|
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.countryCode.addTextChangedListener(new CountryCodeChangedListener());
|
||||||
this.number.addTextChangedListener(new NumberChangedListener());
|
this.number.addTextChangedListener(new NumberChangedListener());
|
||||||
@ -388,13 +401,14 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
restoreButton.setIndeterminateProgressMode(true);
|
restoreButton.setIndeterminateProgressMode(true);
|
||||||
restoreButton.setProgress(50);
|
restoreButton.setProgress(50);
|
||||||
|
|
||||||
|
final String passphrase = prompt.getText().toString();
|
||||||
|
|
||||||
new AsyncTask<Void, Void, BackupImportResult>() {
|
new AsyncTask<Void, Void, BackupImportResult>() {
|
||||||
@Override
|
@Override
|
||||||
protected BackupImportResult doInBackground(Void... voids) {
|
protected BackupImportResult doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
Context context = RegistrationActivity.this;
|
Context context = RegistrationActivity.this;
|
||||||
String passphrase = prompt.getText().toString();
|
SQLiteDatabase database = DatabaseFactory.getBackupDatabase(context);
|
||||||
SQLiteDatabase database = DatabaseFactory.getBackupDatabase(context);
|
|
||||||
|
|
||||||
FullBackupImporter.importFile(context,
|
FullBackupImporter.importFile(context,
|
||||||
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret(),
|
||||||
@ -498,9 +512,9 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private void requestVerificationCode(@NonNull String e164number, boolean gcmSupported, boolean smsRetrieverSupported) {
|
private void requestVerificationCode(@NonNull String e164number, boolean gcmSupported, boolean smsRetrieverSupported) {
|
||||||
new AsyncTask<Void, Void, Pair<String, Optional<String>>> () {
|
new AsyncTask<Void, Void, VerificationRequestResult> () {
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable Pair<String, Optional<String>> doInBackground(Void... voids) {
|
protected @NonNull VerificationRequestResult doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
markAsVerifying(true);
|
markAsVerifying(true);
|
||||||
|
|
||||||
@ -515,29 +529,34 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
}
|
}
|
||||||
|
|
||||||
accountManager = AccountManagerFactory.createManager(RegistrationActivity.this, e164number, password);
|
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) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "Error during account registration", 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) {
|
protected void onPostExecute(@NonNull VerificationRequestResult result) {
|
||||||
if (result == null) {
|
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();
|
Toast.makeText(RegistrationActivity.this, R.string.RegistrationActivity_unable_to_connect_to_service, Toast.LENGTH_LONG).show();
|
||||||
createButton.setIndeterminateProgressMode(false);
|
createButton.setIndeterminateProgressMode(false);
|
||||||
createButton.setProgress(0);
|
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);
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void requestCaptcha(boolean isSms) {
|
||||||
|
startActivityForResult(CaptchaActivity.getIntent(this, isSms), CAPTCHA);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleVerificationCodeReceived(@Nullable String code) {
|
private void handleVerificationCodeReceived(@Nullable String code) {
|
||||||
List<Integer> parsedCode = convertVerificationCodeToDigits(code);
|
List<Integer> parsedCode = convertVerificationCodeToDigits(code);
|
||||||
|
|
||||||
@ -693,7 +712,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());
|
accountManager.requestVoiceVerificationCode(Locale.getDefault(), registrationState.captchaToken);
|
||||||
|
} catch (CaptchaRequiredException e) {
|
||||||
|
requestCaptcha(false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
@ -892,7 +913,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View widget) {
|
public void onClick(View widget) {
|
||||||
displayInitialView(false);
|
displayInitialView(false);
|
||||||
registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, null);
|
registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 static class RegistrationState {
|
||||||
private enum State {
|
private enum State {
|
||||||
INITIAL, VERIFYING, CHECKING, PIN
|
INITIAL, VERIFYING, CHECKING, PIN
|
||||||
}
|
}
|
||||||
|
|
||||||
private final State state;
|
private final State state;
|
||||||
private final String e164number;
|
private final String e164number;
|
||||||
private final String password;
|
private final String password;
|
||||||
private final Optional<String> gcmToken;
|
private final Optional<String> gcmToken;
|
||||||
|
private final Optional<String> captchaToken;
|
||||||
|
|
||||||
RegistrationState(State state, String e164number, String password, Optional<String> gcmToken) {
|
RegistrationState(State state, String e164number, String password, Optional<String> gcmToken, Optional<String> captchaToken) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.e164number = e164number;
|
this.e164number = e164number;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.gcmToken = gcmToken;
|
this.gcmToken = gcmToken;
|
||||||
|
this.captchaToken = captchaToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegistrationState(State state, RegistrationState previous) {
|
RegistrationState(State state, RegistrationState previous) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.e164number = previous.e164number;
|
this.e164number = previous.e164number;
|
||||||
this.password = previous.password;
|
this.password = previous.password;
|
||||||
this.gcmToken = previous.gcmToken;
|
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