Require device unlock rather than account password to change password

Stephen Paul Weber created

More secure for the magic create case, and more likely the user remembers it.

Change summary

src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java |  6 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java    | 24 
2 files changed, 28 insertions(+), 2 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java 🔗

@@ -23,7 +23,7 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 			if (mAccount != null) {
 				final String currentPassword = mCurrentPassword.getText().toString();
 				final String newPassword = mNewPassword.getText().toString();
-				if (!mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(mAccount.getPassword())) {
+				if (!(mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || didUnlock) && !currentPassword.equals(mAccount.getPassword())) {
 					mCurrentPassword.requestFocus();
 					mCurrentPasswordLayout.setError(getString(R.string.account_status_unauthorized));
 					removeErrorsOnAllBut(mCurrentPasswordLayout);
@@ -46,11 +46,12 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 	private TextInputLayout mNewPasswordLayout;
 	private TextInputLayout mCurrentPasswordLayout;
 	private Account mAccount;
+	private boolean didUnlock = false;
 
 	@Override
 	void onBackendConnected() {
 		this.mAccount = extractAccount(getIntent());
-		if (this.mAccount != null && this.mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
+		if (this.mAccount != null && (this.mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || didUnlock)) {
 			this.mCurrentPasswordLayout.setVisibility(View.GONE);
 		} else {
 			this.mCurrentPassword.setVisibility(View.VISIBLE);
@@ -79,6 +80,7 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 	protected void onStart() {
 		super.onStart();
 		Intent intent = getIntent();
+		this.didUnlock = intent.getBooleanExtra("did_unlock", false);
 		String password = intent != null ? intent.getStringExtra("password") : null;
 		if (password != null) {
 			this.mNewPassword.getEditableText().clear();

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -1,8 +1,10 @@
 package eu.siacs.conversations.ui;
 
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
@@ -94,6 +96,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     private static final int REQUEST_DATA_SAVER = 0xf244;
     private static final int REQUEST_CHANGE_STATUS = 0xee11;
     private static final int REQUEST_ORBOT = 0xff22;
+    private static final int REQUEST_UNLOCK = 0xff23;
     private final PendingItem<PresenceTemplate> mPendingPresenceTemplate = new PendingItem<>();
     private AlertDialog mCaptchaDialog = null;
     private Jid jidToEdit;
@@ -141,6 +144,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     private XmppUri pendingUri = null;
     private boolean mUseTor;
     private ActivityEditAccountBinding binding;
+    private String newPassword = null;
     private final OnClickListener mSaveButtonClickListener = new OnClickListener() {
 
         @Override
@@ -485,6 +489,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                 Log.d(Config.LOGTAG, "pgp result not ok");
             }
         }
+        if (requestCode == REQUEST_UNLOCK) {
+            if (resultCode == RESULT_OK) {
+                openChangePassword(true);
+            } else {
+                this.newPassword = null;
+            }
+        }
     }
 
     @Override
@@ -919,11 +930,24 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     private void gotoChangePassword(String newPassword) {
+        this.newPassword = newPassword;
+        KeyguardManager keyguardManager = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
+        Intent credentialsIntent = keyguardManager.createConfirmDeviceCredentialIntent("Unlock required", "Please unlock in order to change your password");
+        if (credentialsIntent == null) {
+            openChangePassword(false);
+        } else {
+            startActivityForResult(credentialsIntent, REQUEST_UNLOCK);
+        }
+    }
+
+    private void openChangePassword(boolean didUnlock) {
         final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
         changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toEscapedString());
+        changePasswordIntent.putExtra("did_unlock", didUnlock);
         if (newPassword != null) {
             changePasswordIntent.putExtra("password", newPassword);
         }
+        this.newPassword = null;
         startActivity(changePasswordIntent);
     }