package com.greenaddress.greenbits.ui;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.text.InputType;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import com.greenaddress.greenbits.QrBitmap;
import com.google.common.collect.ImmutableMap;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TwoFactorActivity extends GaActivity {
private String mMethod; // Current 2FA Method
private Map<String, String> mLocalizedMap; // 2FA method to localized description
private Button mContinueButton;
private TextView mPromptText;
private ProgressBar mProgressBar;
private EditText mCodeText;
private void setView(final int id) {
setContentView(id);
mContinueButton = UI.find(this, R.id.continueButton);
mPromptText = UI.find(this, R.id.prompt);
mProgressBar = UI.find(this, R.id.progressBar);
mCodeText = UI.find(this, R.id.code);
}
private String getTypeString(final String fmt, final String type) {
return new Formatter().format(fmt, type).toString();
}
@Override
protected void onCreateWithService(final Bundle savedInstanceState) {
if (mService.getTwoFactorConfig() == null) {
finish();
return;
}
mMethod = getIntent().getStringExtra("method");
mLocalizedMap = UI.getTwoFactorLookup(getResources());
setTitle(getTypeString(getTitle().toString(), mLocalizedMap.get(mMethod)));
final List<String> enabledMethods = mService.getEnabledTwoFactorMethods();
if (enabledMethods.size() > 1) {
// Multiple 2FA options enabled - Allow the user to choose
setView(R.layout.activity_two_factor_1_choose);
final RadioGroup group = UI.find(this, R.id.radioGroup);
group.removeViews(0, group.getChildCount());
for (int i = 0; i < enabledMethods.size(); ++i) {
final RadioButton b = new RadioButton(TwoFactorActivity.this);
b.setText(mLocalizedMap.get(enabledMethods.get(i)));
b.setId(i);
group.addView(b);
}
group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final RadioGroup group, final int checkedId) {
mContinueButton.setEnabled(true);
}
});
mContinueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
final int checked = group.getCheckedRadioButtonId();
showProvideAuthCode(2, enabledMethods.get(checked));
}
});
} else if (enabledMethods.size() == 1) {
// just one 2FA enabled - go straight to code verification
showProvideAuthCode(1, enabledMethods.get(0));
} else
// no 2FA enabled - go straight to 2FA details
if (mMethod.equals("gauth"))
showGauthDetails(1, 1, null);
else
showProvideDetails(1, 2, null);
}
private Map<String, String> make2FAData(final String method, final String code) {
if (code == null)
return new HashMap<>();
return ImmutableMap.of("method", method, "code", code);
}
private void showProvideDetails(final int stepNum, final int numSteps, final String proxyCode) {
setView(R.layout.activity_two_factor_3_provide_details);
final boolean isEmail = mMethod.equals("email");
final int resId = isEmail ? R.string.emailAddress : R.string.phoneNumber;
final String type = getResources().getString(resId);
mPromptText.setText(getTypeString(UI.getText(mPromptText), type));
if (!isEmail)
UI.hide(UI.find(this, R.id.emailNotices));
mProgressBar.setProgress(stepNum);
mProgressBar.setMax(numSteps);
final TextView detailsText = UI.find(this, R.id.details);
detailsText.setInputType(
isEmail ?
InputType.TYPE_CLASS_TEXT :
InputType.TYPE_CLASS_PHONE
);
mContinueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
final String details = UI.getText(detailsText).trim();
if (details.isEmpty())
return;
UI.disable(mContinueButton);
final Map<String, String> twoFacData = make2FAData("proxy", proxyCode);
CB.after(mService.initEnableTwoFac(mMethod, details, twoFacData),
new CB.Toast<Boolean>(TwoFactorActivity.this, mContinueButton) {
@Override
public void onSuccess(final Boolean result) {
runOnUiThread(new Runnable() {
public void run() {
showProvideConfirmationCode(stepNum + 1, numSteps);
}
});
}
});
}
});
}
private void showProvideAuthCode(final int stepNum, final String method) {
final int numSteps = stepNum + (mMethod.equals("gauth") ? 1 : 2);
final String localizedName = mLocalizedMap.get(method);
if (!method.equals("gauth"))
mService.requestTwoFacCode(method, "enable_2fa",
ImmutableMap.of("method", mMethod));
setView(R.layout.activity_two_factor_2_4_provide_code);
final TextView descriptionText = UI.find(this, R.id.description);
descriptionText.setText(R.string.twoFacProvideAuthCodeDescription);
mPromptText.setText(getTypeString(UI.getText(mPromptText), localizedName));
mProgressBar.setProgress(stepNum);
mProgressBar.setMax(numSteps);
mContinueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
mContinueButton.setEnabled(false);
final Map<String, String> data = make2FAData(method, UI.getText(mCodeText).trim());
CB.after(mService.requestTwoFacCode("proxy", mMethod, data),
new CB.Toast<Object>(TwoFactorActivity.this, mContinueButton) {
@Override
public void onSuccess(final Object proxyCode) {
runOnUiThread(new Runnable() {
public void run() {
if (mMethod.equals("gauth"))
showGauthDetails(stepNum + 1, numSteps, (String) proxyCode);
else
showProvideDetails(stepNum + 1, numSteps, (String) proxyCode);
}
});
}
});
}
});
}
private void showGauthDetails(final int stepNum, final int numSteps, final String proxyCode) {
setView(R.layout.activity_two_factor_3_gauth_details);
final ImageView imageView = UI.find(this, R.id.imageView);
final TextView textCode = UI.find(this, R.id.textCode);
mProgressBar.setProgress(stepNum);
mProgressBar.setMax(numSteps);
final String gauth_url = (String) mService.getTwoFactorConfig().get("gauth_url");
final BitmapDrawable bd = new BitmapDrawable(getResources(), new QrBitmap(gauth_url, 0).getQRCode());
bd.setFilterBitmap(false);
imageView.setImageDrawable(bd);
final String gauthCode = gauth_url.split("=")[1];
textCode.setText(getString(R.string.twoFacGauthTextCode, gauthCode));
textCode.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(final View v) {
final ClipboardManager clipboard = (ClipboardManager)
getSystemService(Context.CLIPBOARD_SERVICE);
final ClipData clip = ClipData.newPlainText("data", gauthCode);
clipboard.setPrimaryClip(clip);
TwoFactorActivity.this.toast(R.string.warnOnPaste);
}
}
);
mContinueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
final Map<String, String> twoFacData = make2FAData("proxy", proxyCode);
mContinueButton.setEnabled(false);
CB.after(mService.enableTwoFactor("gauth", UI.getText(mCodeText).trim(), twoFacData),
new CB.Toast<Boolean>(TwoFactorActivity.this, mContinueButton) {
@Override
public void onSuccess(final Boolean result) {
setResult(RESULT_OK);
finishOnUiThread();
}
});
}
});
}
private void showProvideConfirmationCode(final int stepNum, final int numSteps) {
setView(R.layout.activity_two_factor_2_4_provide_code);
mPromptText.setText(getTypeString(UI.getText(mPromptText), mLocalizedMap.get(mMethod)));
mProgressBar.setProgress(stepNum);
mProgressBar.setMax(numSteps);
mContinueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
final String enteredCode = UI.getText(mCodeText).trim();
if (enteredCode.length() != 6)
return;
mContinueButton.setEnabled(false);
CB.after(mService.enableTwoFactor(mMethod, enteredCode, null),
new CB.Toast<Boolean>(TwoFactorActivity.this, mContinueButton) {
@Override
public void onSuccess(final Boolean result) {
setResult(RESULT_OK);
finishOnUiThread();
}
});
}
});
}
}