allow spend with fingerprint only (#674)

This commit is contained in:
m2049r 2020-09-13 18:26:36 +02:00 committed by GitHub
parent 10f2bc6561
commit 82b4d66987
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 228 deletions

View File

@ -315,10 +315,14 @@ public class LoginActivity extends BaseActivity
if (WalletManager.getInstance().walletExists(walletFile)) {
Helper.promptPassword(LoginActivity.this, walletName, true, new Helper.PasswordAction() {
@Override
public void action(String walletName, String password, boolean fingerprintUsed) {
public void act(String walletName, String password, boolean fingerprintUsed) {
if (checkDevice(walletName, password))
startDetails(walletFile, password, GenerateReviewFragment.VIEW_TYPE_DETAILS);
}
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
});
} else { // this cannot really happen as we prefilter choices
Timber.e("Wallet missing: %s", walletName);
@ -348,10 +352,14 @@ public class LoginActivity extends BaseActivity
if (WalletManager.getInstance().walletExists(walletFile)) {
Helper.promptPassword(LoginActivity.this, walletName, false, new Helper.PasswordAction() {
@Override
public void action(String walletName, String password, boolean fingerprintUsed) {
public void act(String walletName, String password, boolean fingerprintUsed) {
if (checkDevice(walletName, password))
startReceive(walletFile, password);
}
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
});
} else { // this cannot really happen as we prefilter choices
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
@ -1306,10 +1314,15 @@ public class LoginActivity extends BaseActivity
Helper.promptPassword(LoginActivity.this, walletName, false,
new Helper.PasswordAction() {
@Override
public void action(String walletName, String password, boolean fingerprintUsed) {
public void act(String walletName, String password, boolean fingerprintUsed) {
if (checkDevice(walletName, password))
startWallet(walletName, password, fingerprintUsed, streetmode);
}
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
});
} else { // this cannot really happen as we prefilter choices
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();

View File

@ -88,7 +88,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private ActionBarDrawerToggle drawerToggle;
private Toolbar toolbar;
private boolean needVerifyIdentity;
private boolean requestStreetMode = false;
private String password;
@ -142,7 +141,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private void enableStreetMode(boolean enable) {
if (enable) {
needVerifyIdentity = true;
streetMode = getWallet().getDaemonBlockChainHeight();
} else {
streetMode = 0;
@ -200,7 +198,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
if (extras != null) {
acquireWakeLock();
String walletId = extras.getString(REQUEST_ID);
needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED);
// we can set the streetmode height AFTER opening the wallet
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
password = extras.getString(REQUEST_PW);
@ -333,7 +330,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private void onDisableStreetMode() {
Helper.promptPassword(WalletActivity.this, getWallet().getName(), false, new Helper.PasswordAction() {
@Override
public void action(String walletName, String password, boolean fingerprintUsed) {
public void act(String walletName, String password, boolean fingerprintUsed) {
runOnUiThread(new Runnable() {
@Override
public void run() {
@ -342,6 +339,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
}
});
}
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
});
}
@ -855,17 +856,16 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
final Bundle extras = new Bundle();
extras.putString(GenerateReviewFragment.REQUEST_TYPE, GenerateReviewFragment.VIEW_TYPE_WALLET);
if (needVerifyIdentity) {
Helper.promptPassword(WalletActivity.this, getWallet().getName(), true, new Helper.PasswordAction() {
@Override
public void action(String walletName, String password, boolean fingerprintUsed) {
public void act(String walletName, String password, boolean fingerprintUsed) {
replaceFragment(new GenerateReviewFragment(), null, extras);
needVerifyIdentity = false;
}
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
});
} else {
replaceFragment(new GenerateReviewFragment(), null, extras);
}
break;
case DialogInterface.BUTTON_NEGATIVE:
@ -1003,12 +1003,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
return getWallet().getUnlockedBalance();
}
@Override
public boolean verifyWalletPassword(String password) {
String walletPassword = Helper.getWalletPassword(getApplicationContext(), getWalletName(), password);
return walletPassword != null;
}
@Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {

View File

@ -346,103 +346,16 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
}
public void preSend() {
final Activity activity = getActivity();
View promptsView = getLayoutInflater().inflate(R.layout.prompt_password, null);
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(activity);
alertDialogBuilder.setView(promptsView);
final TextInputLayout etPassword = promptsView.findViewById(R.id.etPassword);
etPassword.setHint(getString(R.string.prompt_send_password));
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
Helper.promptPassword(getContext(), getActivityCallback().getWalletName(), false, new Helper.PasswordAction() {
@Override
public void afterTextChanged(Editable s) {
if (etPassword.getError() != null) {
etPassword.setError(null);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
});
alertDialogBuilder
.setCancelable(false)
.setPositiveButton(getString(R.string.label_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) {
dialog.dismiss();
Helper.hideKeyboardAlways(activity);
public void act(String walletName, String password, boolean fingerprintUsed) {
send();
} else {
etPassword.setError(getString(R.string.bad_password));
}
}
})
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(activity);
dialog.cancel();
public void fail(String walletName, String password, boolean fingerprintUsed) {
bSend.setEnabled(sendCountdown > 0); // allow to try again
}
});
final android.app.AlertDialog passwordDialog = alertDialogBuilder.create();
passwordDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
Button button = ((android.app.AlertDialog) dialog).getButton(android.app.AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) {
Helper.hideKeyboardAlways(activity);
passwordDialog.dismiss();
send();
} else {
etPassword.setError(getString(R.string.bad_password));
}
}
});
}
});
Helper.showKeyboard(passwordDialog);
// accept keyboard "ok"
etPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) {
Helper.hideKeyboardAlways(activity);
passwordDialog.dismiss();
send();
} else {
etPassword.setError(getString(R.string.bad_password));
}
return true;
}
return false;
}
});
if (Helper.preventScreenshot()) {
passwordDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
passwordDialog.show();
}
// creates a pending transaction and calls us back with transactionCreated()

View File

@ -141,8 +141,13 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
void send() {
sendListener.commitTransaction();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
pbProgressSend.setVisibility(View.VISIBLE);
}
});
}
@Override
public void sendFailed(String errorText) {
@ -225,103 +230,16 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
}
public void preSend() {
final Activity activity = getActivity();
View promptsView = getLayoutInflater().inflate(R.layout.prompt_password, null);
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(activity);
alertDialogBuilder.setView(promptsView);
final TextInputLayout etPassword = promptsView.findViewById(R.id.etPassword);
etPassword.setHint(getString(R.string.prompt_send_password));
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
Helper.promptPassword(getContext(), getActivityCallback().getWalletName(), false, new Helper.PasswordAction() {
@Override
public void afterTextChanged(Editable s) {
if (etPassword.getError() != null) {
etPassword.setError(null);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
});
alertDialogBuilder
.setCancelable(false)
.setPositiveButton(getString(R.string.label_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) {
dialog.dismiss();
Helper.hideKeyboardAlways(activity);
public void act(String walletName, String password, boolean fingerprintUsed) {
send();
} else {
etPassword.setError(getString(R.string.bad_password));
}
}
})
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(activity);
dialog.cancel();
public void fail(String walletName, String password, boolean fingerprintUsed) {
bSend.setEnabled(true); // allow to try again
}
});
final android.app.AlertDialog passwordDialog = alertDialogBuilder.create();
passwordDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
Button button = ((android.app.AlertDialog) dialog).getButton(android.app.AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) {
Helper.hideKeyboardAlways(activity);
passwordDialog.dismiss();
send();
} else {
etPassword.setError(getString(R.string.bad_password));
}
}
});
}
});
Helper.showKeyboard(passwordDialog);
// accept keyboard "ok"
etPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
String pass = etPassword.getEditText().getText().toString();
if (getActivityCallback().verifyWalletPassword(pass)) {
Helper.hideKeyboardAlways(activity);
passwordDialog.dismiss();
send();
} else {
etPassword.setError(getString(R.string.bad_password));
}
return true;
}
return false;
}
});
if (Helper.preventScreenshot()) {
passwordDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
passwordDialog.show();
}
// creates a pending transaction and calls us back with transactionCreated()

View File

@ -75,7 +75,7 @@ public class SendFragment extends Fragment
void onPrepareSend(String tag, TxData data);
boolean verifyWalletPassword(String password);
String getWalletName();
void onSend(UserNotes notes);

View File

@ -417,7 +417,7 @@ public class Helper {
}
static AlertDialog openDialog = null; // for preventing opening of multiple dialogs
static AsyncTask<Void, Void, Boolean> loginTask = null;
static AsyncTask<Void, Void, Boolean> passwordTask = null;
static public void promptPassword(final Context context, final String wallet, boolean fingerprintDisabled, final PasswordAction action) {
if (openDialog != null) return; // we are already asking for password
@ -442,11 +442,11 @@ public class Helper {
final AtomicBoolean incorrectSavedPass = new AtomicBoolean(false);
class LoginWalletTask extends AsyncTask<Void, Void, Boolean> {
class PasswordTask extends AsyncTask<Void, Void, Boolean> {
private String pass;
private boolean fingerprintUsed;
LoginWalletTask(String pass, boolean fingerprintUsed) {
PasswordTask(String pass, boolean fingerprintUsed) {
this.pass = pass;
this.fingerprintUsed = fingerprintUsed;
}
@ -488,7 +488,7 @@ public class Helper {
etPassword.setError(context.getString(R.string.bad_password));
}
}
loginTask = null;
passwordTask = null;
}
}
@ -521,9 +521,9 @@ public class Helper {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways((Activity) context);
cancelSignal.cancel();
if (loginTask != null) {
loginTask.cancel(true);
loginTask = null;
if (passwordTask != null) {
passwordTask.cancel(true);
passwordTask = null;
}
dialog.cancel();
openDialog = null;
@ -552,9 +552,9 @@ public class Helper {
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
try {
String userPass = KeyStoreHelper.loadWalletUserPass(context, wallet);
if (loginTask == null) {
loginTask = new LoginWalletTask(userPass, true);
loginTask.execute();
if (passwordTask == null) {
passwordTask = new PasswordTask(userPass, true);
passwordTask.execute();
}
} catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
etPassword.setError(context.getString(R.string.bad_password));
@ -586,9 +586,9 @@ public class Helper {
@Override
public void onClick(View view) {
String pass = etPassword.getEditText().getText().toString();
if (loginTask == null) {
loginTask = new LoginWalletTask(pass, false);
loginTask.execute();
if (passwordTask == null) {
passwordTask = new PasswordTask(pass, false);
passwordTask.execute();
}
}
});
@ -601,9 +601,9 @@ public class Helper {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
String pass = etPassword.getEditText().getText().toString();
if (loginTask == null) {
loginTask = new LoginWalletTask(pass, false);
loginTask.execute();
if (passwordTask == null) {
passwordTask = new PasswordTask(pass, false);
passwordTask.execute();
}
return true;
}
@ -620,15 +620,18 @@ public class Helper {
}
public interface PasswordAction {
void action(String walletName, String password, boolean fingerprintUsed);
void act(String walletName, String password, boolean fingerprintUsed);
void fail(String walletName, String password, boolean fingerprintUsed);
}
static private boolean processPasswordEntry(Context context, String walletName, String pass, boolean fingerprintUsed, PasswordAction action) {
String walletPassword = Helper.getWalletPassword(context, walletName, pass);
if (walletPassword != null) {
action.action(walletName, walletPassword, fingerprintUsed);
action.act(walletName, walletPassword, fingerprintUsed);
return true;
} else {
action.fail(walletName, walletPassword, fingerprintUsed);
return false;
}
}