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)) { if (WalletManager.getInstance().walletExists(walletFile)) {
Helper.promptPassword(LoginActivity.this, walletName, true, new Helper.PasswordAction() { Helper.promptPassword(LoginActivity.this, walletName, true, new Helper.PasswordAction() {
@Override @Override
public void action(String walletName, String password, boolean fingerprintUsed) { public void act(String walletName, String password, boolean fingerprintUsed) {
if (checkDevice(walletName, password)) if (checkDevice(walletName, password))
startDetails(walletFile, password, GenerateReviewFragment.VIEW_TYPE_DETAILS); 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 } else { // this cannot really happen as we prefilter choices
Timber.e("Wallet missing: %s", walletName); Timber.e("Wallet missing: %s", walletName);
@ -348,10 +352,14 @@ public class LoginActivity extends BaseActivity
if (WalletManager.getInstance().walletExists(walletFile)) { if (WalletManager.getInstance().walletExists(walletFile)) {
Helper.promptPassword(LoginActivity.this, walletName, false, new Helper.PasswordAction() { Helper.promptPassword(LoginActivity.this, walletName, false, new Helper.PasswordAction() {
@Override @Override
public void action(String walletName, String password, boolean fingerprintUsed) { public void act(String walletName, String password, boolean fingerprintUsed) {
if (checkDevice(walletName, password)) if (checkDevice(walletName, password))
startReceive(walletFile, password); startReceive(walletFile, password);
} }
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
}); });
} else { // this cannot really happen as we prefilter choices } else { // this cannot really happen as we prefilter choices
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show(); 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, Helper.promptPassword(LoginActivity.this, walletName, false,
new Helper.PasswordAction() { new Helper.PasswordAction() {
@Override @Override
public void action(String walletName, String password, boolean fingerprintUsed) { public void act(String walletName, String password, boolean fingerprintUsed) {
if (checkDevice(walletName, password)) if (checkDevice(walletName, password))
startWallet(walletName, password, fingerprintUsed, streetmode); startWallet(walletName, password, fingerprintUsed, streetmode);
} }
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
}
}); });
} else { // this cannot really happen as we prefilter choices } else { // this cannot really happen as we prefilter choices
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show(); 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 ActionBarDrawerToggle drawerToggle;
private Toolbar toolbar; private Toolbar toolbar;
private boolean needVerifyIdentity;
private boolean requestStreetMode = false; private boolean requestStreetMode = false;
private String password; private String password;
@ -142,7 +141,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private void enableStreetMode(boolean enable) { private void enableStreetMode(boolean enable) {
if (enable) { if (enable) {
needVerifyIdentity = true;
streetMode = getWallet().getDaemonBlockChainHeight(); streetMode = getWallet().getDaemonBlockChainHeight();
} else { } else {
streetMode = 0; streetMode = 0;
@ -200,7 +198,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
if (extras != null) { if (extras != null) {
acquireWakeLock(); acquireWakeLock();
String walletId = extras.getString(REQUEST_ID); String walletId = extras.getString(REQUEST_ID);
needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED);
// we can set the streetmode height AFTER opening the wallet // we can set the streetmode height AFTER opening the wallet
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE); requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
password = extras.getString(REQUEST_PW); password = extras.getString(REQUEST_PW);
@ -333,7 +330,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
private void onDisableStreetMode() { private void onDisableStreetMode() {
Helper.promptPassword(WalletActivity.this, getWallet().getName(), false, new Helper.PasswordAction() { Helper.promptPassword(WalletActivity.this, getWallet().getName(), false, new Helper.PasswordAction() {
@Override @Override
public void action(String walletName, String password, boolean fingerprintUsed) { public void act(String walletName, String password, boolean fingerprintUsed) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { 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(); final Bundle extras = new Bundle();
extras.putString(GenerateReviewFragment.REQUEST_TYPE, GenerateReviewFragment.VIEW_TYPE_WALLET); extras.putString(GenerateReviewFragment.REQUEST_TYPE, GenerateReviewFragment.VIEW_TYPE_WALLET);
if (needVerifyIdentity) {
Helper.promptPassword(WalletActivity.this, getWallet().getName(), true, new Helper.PasswordAction() { Helper.promptPassword(WalletActivity.this, getWallet().getName(), true, new Helper.PasswordAction() {
@Override @Override
public void action(String walletName, String password, boolean fingerprintUsed) { public void act(String walletName, String password, boolean fingerprintUsed) {
replaceFragment(new GenerateReviewFragment(), null, extras); replaceFragment(new GenerateReviewFragment(), null, extras);
needVerifyIdentity = false; }
@Override
public void fail(String walletName, String password, boolean fingerprintUsed) {
} }
}); });
} else {
replaceFragment(new GenerateReviewFragment(), null, extras);
}
break; break;
case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEGATIVE:
@ -1003,12 +1003,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
return getWallet().getUnlockedBalance(); return getWallet().getUnlockedBalance();
} }
@Override
public boolean verifyWalletPassword(String password) {
String walletPassword = Helper.getWalletPassword(getApplicationContext(), getWalletName(), password);
return walletPassword != null;
}
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) { if (drawer.isDrawerOpen(GravityCompat.START)) {

View File

@ -346,103 +346,16 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
} }
public void preSend() { public void preSend() {
final Activity activity = getActivity(); Helper.promptPassword(getContext(), getActivityCallback().getWalletName(), false, new Helper.PasswordAction() {
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() {
@Override @Override
public void afterTextChanged(Editable s) { public void act(String walletName, String password, boolean fingerprintUsed) {
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);
send(); send();
} else {
etPassword.setError(getString(R.string.bad_password));
} }
}
}) public void fail(String walletName, String password, boolean fingerprintUsed) {
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(activity);
dialog.cancel();
bSend.setEnabled(sendCountdown > 0); // allow to try again 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() // 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() { void send() {
sendListener.commitTransaction(); sendListener.commitTransaction();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
pbProgressSend.setVisibility(View.VISIBLE); pbProgressSend.setVisibility(View.VISIBLE);
} }
});
}
@Override @Override
public void sendFailed(String errorText) { public void sendFailed(String errorText) {
@ -225,103 +230,16 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
} }
public void preSend() { public void preSend() {
final Activity activity = getActivity(); Helper.promptPassword(getContext(), getActivityCallback().getWalletName(), false, new Helper.PasswordAction() {
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() {
@Override @Override
public void afterTextChanged(Editable s) { public void act(String walletName, String password, boolean fingerprintUsed) {
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);
send(); send();
} else {
etPassword.setError(getString(R.string.bad_password));
} }
}
}) public void fail(String walletName, String password, boolean fingerprintUsed) {
.setNegativeButton(getString(R.string.label_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(activity);
dialog.cancel();
bSend.setEnabled(true); // allow to try again 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() // 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); void onPrepareSend(String tag, TxData data);
boolean verifyWalletPassword(String password); String getWalletName();
void onSend(UserNotes notes); void onSend(UserNotes notes);

View File

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