2015-01-20 05:24:10 +01:00
|
|
|
package org.thoughtcrime.securesms;
|
|
|
|
|
|
|
|
import android.content.Context;
|
2015-01-24 05:38:45 +01:00
|
|
|
import android.content.DialogInterface;
|
|
|
|
import android.content.DialogInterface.OnDismissListener;
|
2015-01-20 05:24:10 +01:00
|
|
|
import android.net.Uri;
|
|
|
|
import android.os.Bundle;
|
2014-12-15 21:25:55 +01:00
|
|
|
import android.support.annotation.NonNull;
|
2015-01-24 05:38:45 +01:00
|
|
|
import android.text.SpannableStringBuilder;
|
2015-01-20 05:24:10 +01:00
|
|
|
import android.util.Log;
|
2015-01-24 05:38:45 +01:00
|
|
|
import android.view.Window;
|
2015-01-20 05:24:10 +01:00
|
|
|
import android.widget.Toast;
|
|
|
|
|
2015-01-24 05:38:45 +01:00
|
|
|
import com.afollestad.materialdialogs.MaterialDialog;
|
|
|
|
import com.afollestad.materialdialogs.MaterialDialog.Builder;
|
|
|
|
import com.afollestad.materialdialogs.MaterialDialog.ButtonCallback;
|
|
|
|
|
2015-01-20 05:24:10 +01:00
|
|
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|
|
|
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
|
|
|
|
import org.thoughtcrime.securesms.util.Base64;
|
|
|
|
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
|
|
|
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
|
|
|
import org.whispersystems.libaxolotl.InvalidKeyException;
|
|
|
|
import org.whispersystems.libaxolotl.ecc.Curve;
|
|
|
|
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
|
|
|
import org.whispersystems.textsecure.api.TextSecureAccountManager;
|
|
|
|
import org.whispersystems.textsecure.api.push.exceptions.NotFoundException;
|
2015-06-20 07:02:10 +02:00
|
|
|
import org.whispersystems.textsecure.internal.push.DeviceLimitExceededException;
|
2015-01-20 05:24:10 +01:00
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
2015-01-24 05:38:45 +01:00
|
|
|
import static org.thoughtcrime.securesms.util.SpanUtil.small;
|
|
|
|
|
2015-01-20 05:24:10 +01:00
|
|
|
public class DeviceProvisioningActivity extends PassphraseRequiredActionBarActivity {
|
|
|
|
|
|
|
|
private static final String TAG = DeviceProvisioningActivity.class.getSimpleName();
|
|
|
|
|
|
|
|
private Uri uri;
|
|
|
|
private MasterSecret masterSecret;
|
|
|
|
|
|
|
|
@Override
|
2014-12-15 21:25:55 +01:00
|
|
|
protected void onPreCreate() {
|
2015-01-24 05:38:45 +01:00
|
|
|
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
2014-12-15 21:25:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle bundle, @NonNull MasterSecret masterSecret) {
|
|
|
|
this.masterSecret = masterSecret;
|
2015-01-24 05:38:45 +01:00
|
|
|
getSupportActionBar().hide();
|
2015-01-20 05:24:10 +01:00
|
|
|
initializeResources();
|
2015-01-24 05:38:45 +01:00
|
|
|
|
|
|
|
SpannableStringBuilder content = new SpannableStringBuilder();
|
2015-01-24 19:15:13 +01:00
|
|
|
content.append(getString(R.string.DeviceProvisioningActivity_content_intro))
|
2015-01-24 05:38:45 +01:00
|
|
|
.append("\n")
|
2015-01-24 19:15:13 +01:00
|
|
|
.append(small(getString(R.string.DeviceProvisioningActivity_content_bullets)));
|
2015-01-24 05:38:45 +01:00
|
|
|
|
2015-01-24 19:15:13 +01:00
|
|
|
new Builder(this).title(getString(R.string.DeviceProvisioningActivity_link_this_device))
|
2015-01-24 05:38:45 +01:00
|
|
|
.iconRes(R.drawable.icon_dialog)
|
|
|
|
.content(content)
|
2015-01-24 19:15:13 +01:00
|
|
|
.positiveText(R.string.DeviceProvisioningActivity_continue)
|
|
|
|
.negativeText(R.string.DeviceProvisioningActivity_cancel)
|
2015-01-24 05:38:45 +01:00
|
|
|
.positiveColorRes(R.color.textsecure_primary)
|
|
|
|
.negativeColorRes(R.color.gray50)
|
|
|
|
.autoDismiss(false)
|
|
|
|
.callback(new ButtonCallback() {
|
|
|
|
@Override
|
|
|
|
public void onPositive(MaterialDialog dialog) {
|
|
|
|
handleProvisioning(dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onNegative(MaterialDialog dialog) {
|
|
|
|
dialog.dismiss();
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.dismissListener(new OnDismissListener() {
|
|
|
|
@Override
|
|
|
|
public void onDismiss(DialogInterface dialog) {
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.show();
|
2015-01-20 05:24:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void initializeResources() {
|
2015-01-24 05:38:45 +01:00
|
|
|
this.uri = getIntent().getData();
|
2015-01-20 05:24:10 +01:00
|
|
|
}
|
|
|
|
|
2015-01-24 05:38:45 +01:00
|
|
|
private void handleProvisioning(final MaterialDialog dialog) {
|
|
|
|
new ProgressDialogAsyncTask<Void, Void, Integer>(this,
|
2015-01-24 19:15:13 +01:00
|
|
|
R.string.DeviceProvisioningActivity_content_progress_title,
|
|
|
|
R.string.DeviceProvisioningActivity_content_progress_content)
|
2015-01-24 05:38:45 +01:00
|
|
|
{
|
2015-06-20 07:02:10 +02:00
|
|
|
private static final int SUCCESS = 0;
|
|
|
|
private static final int NO_DEVICE = 1;
|
|
|
|
private static final int NETWORK_ERROR = 2;
|
|
|
|
private static final int KEY_ERROR = 3;
|
|
|
|
private static final int LIMIT_EXCEEDED = 4;
|
2015-01-20 05:24:10 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected Integer doInBackground(Void... params) {
|
|
|
|
try {
|
|
|
|
Context context = DeviceProvisioningActivity.this;
|
|
|
|
TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context);
|
|
|
|
String verificationCode = accountManager.getNewDeviceVerificationCode();
|
|
|
|
String ephemeralId = uri.getQueryParameter("uuid");
|
|
|
|
String publicKeyEncoded = uri.getQueryParameter("pub_key");
|
|
|
|
ECPublicKey publicKey = Curve.decodePoint(Base64.decode(publicKeyEncoded), 0);
|
|
|
|
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
|
|
|
|
|
|
|
|
accountManager.addDevice(ephemeralId, publicKey, identityKeyPair, verificationCode);
|
|
|
|
return SUCCESS;
|
|
|
|
|
2015-06-20 07:02:10 +02:00
|
|
|
|
2015-01-20 05:24:10 +01:00
|
|
|
} catch (NotFoundException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
return NO_DEVICE;
|
2015-06-20 07:02:10 +02:00
|
|
|
} catch (DeviceLimitExceededException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
return LIMIT_EXCEEDED;
|
2015-01-20 05:24:10 +01:00
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
return NETWORK_ERROR;
|
|
|
|
} catch (InvalidKeyException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
return KEY_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onPostExecute(Integer result) {
|
|
|
|
super.onPostExecute(result);
|
|
|
|
|
|
|
|
Context context = DeviceProvisioningActivity.this;
|
|
|
|
|
|
|
|
switch (result) {
|
|
|
|
case SUCCESS:
|
2015-01-24 19:15:13 +01:00
|
|
|
Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_success, Toast.LENGTH_SHORT).show();
|
2015-01-20 05:24:10 +01:00
|
|
|
break;
|
|
|
|
case NO_DEVICE:
|
2015-01-24 19:15:13 +01:00
|
|
|
Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_no_device, Toast.LENGTH_LONG).show();
|
2015-01-20 05:24:10 +01:00
|
|
|
break;
|
|
|
|
case NETWORK_ERROR:
|
2015-01-24 19:15:13 +01:00
|
|
|
Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_network_error, Toast.LENGTH_LONG).show();
|
2015-01-20 05:24:10 +01:00
|
|
|
break;
|
|
|
|
case KEY_ERROR:
|
2015-01-24 19:15:13 +01:00
|
|
|
Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_key_error, Toast.LENGTH_LONG).show();
|
2015-01-20 05:24:10 +01:00
|
|
|
break;
|
2015-06-20 07:02:10 +02:00
|
|
|
case LIMIT_EXCEEDED:
|
|
|
|
Toast.makeText(context, R.string.DeviceProvisioningActivity_sorry_you_have_too_many_devices_registered_already, Toast.LENGTH_LONG).show();
|
|
|
|
break;
|
2015-01-20 05:24:10 +01:00
|
|
|
}
|
2015-01-24 05:38:45 +01:00
|
|
|
dialog.dismiss();
|
2015-01-20 05:24:10 +01:00
|
|
|
}
|
|
|
|
}.execute();
|
|
|
|
}
|
|
|
|
}
|