prevent user from accidentally changing password after using magic create

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/Account.java               |  1 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java |  1 
src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java      | 22 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java         | 57 
src/main/java/eu/siacs/conversations/ui/MagicCreateActivity.java         |  3 
src/main/res/layout/activity_change_password.xml                         | 22 
src/main/res/values/strings.xml                                          |  1 
7 files changed, 84 insertions(+), 23 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/Account.java 🔗

@@ -52,6 +52,7 @@ public class Account extends AbstractEntity {
 	public static final int OPTION_DISABLED = 1;
 	public static final int OPTION_REGISTER = 2;
 	public static final int OPTION_USECOMPRESSION = 3;
+	public static final int OPTION_MAGIC_CREATE = 4;
 	public final HashSet<Pair<String, String>> inProgressDiscoFetches = new HashSet<>();
 
 	public boolean httpUploadAvailable(long filesize) {

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -1513,6 +1513,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 			public void onIqPacketReceived(final Account account, final IqPacket packet) {
 				if (packet.getType() == IqPacket.TYPE.RESULT) {
 					account.setPassword(newPassword);
+					account.setOption(Account.OPTION_MAGIC_CREATE, false);
 					databaseBackend.updateAccount(account);
 					callback.onPasswordChangeSucceeded();
 				} else {

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

@@ -1,9 +1,11 @@
 package eu.siacs.conversations.ui;
 
+import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.Button;
 import android.widget.EditText;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import eu.siacs.conversations.R;
@@ -22,7 +24,7 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 				final String currentPassword = mCurrentPassword.getText().toString();
 				final String newPassword = mNewPassword.getText().toString();
 				final String newPasswordConfirm = mNewPasswordConfirm.getText().toString();
-				if (!currentPassword.equals(mAccount.getPassword())) {
+				if (!mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(mAccount.getPassword())) {
 					mCurrentPassword.requestFocus();
 					mCurrentPassword.setError(getString(R.string.account_status_unauthorized));
 				} else if (!newPassword.equals(newPasswordConfirm)) {
@@ -43,6 +45,7 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 			}
 		}
 	};
+	private TextView mCurrentPasswordLabel;
 	private EditText mCurrentPassword;
 	private EditText mNewPassword;
 	private EditText mNewPasswordConfirm;
@@ -51,7 +54,13 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 	@Override
 	void onBackendConnected() {
 		this.mAccount = extractAccount(getIntent());
-
+		if (this.mAccount != null && this.mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
+			this.mCurrentPasswordLabel.setVisibility(View.GONE);
+			this.mCurrentPassword.setVisibility(View.GONE);
+		} else {
+			this.mCurrentPasswordLabel.setVisibility(View.VISIBLE);
+			this.mCurrentPassword.setVisibility(View.VISIBLE);
+		}
 	}
 
 	@Override
@@ -67,11 +76,20 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 		});
 		this.mChangePasswordButton = (Button) findViewById(R.id.right_button);
 		this.mChangePasswordButton.setOnClickListener(this.mOnChangePasswordButtonClicked);
+		this.mCurrentPasswordLabel = (TextView) findViewById(R.id.current_password_label);
 		this.mCurrentPassword = (EditText) findViewById(R.id.current_password);
 		this.mNewPassword = (EditText) findViewById(R.id.new_password);
 		this.mNewPasswordConfirm = (EditText) findViewById(R.id.new_password_confirm);
 	}
 
+	@Override
+	protected void onStart() {
+		super.onStart();
+		Intent intent = getIntent();
+		String password = intent != null ? intent.getStringExtra("password") : "";
+		this.mNewPassword.getEditableText().append(password);
+	}
+
 	@Override
 	public void onPasswordChangeSucceeded() {
 		runOnUiThread(new Runnable() {

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

@@ -33,6 +33,8 @@ import android.widget.TableRow;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import android.util.Log;
+
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
@@ -109,6 +111,13 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 
 		@Override
 		public void onClick(final View v) {
+			final String password = mPassword.getText().toString();
+			final String passwordConfirm = mPasswordConfirm.getText().toString();
+
+			if (!mInitMode && passwordChangedInMagicCreateMode()) {
+				gotoChangePassword(password);
+				return;
+			}
 			if (mInitMode && mAccount != null) {
 				mAccount.setOption(Account.OPTION_DISABLED, false);
 			}
@@ -173,8 +182,6 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 				mAccountJid.requestFocus();
 				return;
 			}
-			final String password = mPassword.getText().toString();
-			final String passwordConfirm = mPasswordConfirm.getText().toString();
 			if (registerNewAccount) {
 				if (!password.equals(passwordConfirm)) {
 					mPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
@@ -183,6 +190,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 				}
 			}
 			if (mAccount != null) {
+				if (mInitMode && mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
+					mAccount.setOption(Account.OPTION_MAGIC_CREATE, mAccount.getPassword().contains(password));
+				}
 				mAccount.setJid(jid);
 				mAccount.setPort(numericPort);
 				mAccount.setHostname(hostname);
@@ -330,7 +340,13 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 	}
 
 	protected void updateSaveButton() {
-		if (accountInfoEdited() && !mInitMode) {
+		boolean accountInfoEdited = accountInfoEdited();
+
+		if (!mInitMode && passwordChangedInMagicCreateMode()) {
+			this.mSaveButton.setText(R.string.change_password);
+			this.mSaveButton.setEnabled(true);
+			this.mSaveButton.setTextColor(getPrimaryTextColor());
+		} else if (accountInfoEdited && !mInitMode) {
 			this.mSaveButton.setText(R.string.save);
 			this.mSaveButton.setEnabled(true);
 			this.mSaveButton.setTextColor(getPrimaryTextColor());
@@ -349,7 +365,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			if (!mInitMode) {
 				if (mAccount != null && mAccount.isOnlineAndConnected()) {
 					this.mSaveButton.setText(R.string.save);
-					if (!accountInfoEdited()) {
+					if (!accountInfoEdited) {
 						this.mSaveButton.setEnabled(false);
 						this.mSaveButton.setTextColor(getSecondaryTextColor());
 					}
@@ -366,16 +382,28 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 		if (this.mAccount == null) {
 			return false;
 		}
+		return jidEdited() ||
+				!this.mAccount.getPassword().equals(this.mPassword.getText().toString()) ||
+				!this.mAccount.getHostname().equals(this.mHostname.getText().toString()) ||
+				!String.valueOf(this.mAccount.getPort()).equals(this.mPort.getText().toString());
+	}
+
+	protected boolean jidEdited() {
 		final String unmodified;
 		if (Config.DOMAIN_LOCK != null) {
 			unmodified = this.mAccount.getJid().getLocalpart();
 		} else {
 			unmodified = this.mAccount.getJid().toBareJid().toString();
 		}
-		return !unmodified.equals(this.mAccountJid.getText().toString()) ||
-				!this.mAccount.getPassword().equals(this.mPassword.getText().toString()) ||
-				!this.mAccount.getHostname().equals(this.mHostname.getText().toString()) ||
-				!String.valueOf(this.mAccount.getPort()).equals(this.mPort.getText().toString());
+		return !unmodified.equals(this.mAccountJid.getText().toString());
+	}
+
+	protected boolean passwordChangedInMagicCreateMode() {
+		return mAccount != null
+				&& mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)
+				&& !this.mAccount.getPassword().equals(this.mPassword.getText().toString())
+				&& !this.jidEdited()
+				&& mAccount.isOnlineAndConnected();
 	}
 
 	@Override
@@ -582,9 +610,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 				item.setChecked(!item.isChecked());
 				break;
 			case R.id.action_change_password_on_server:
-				final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
-				changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString());
-				startActivity(changePasswordIntent);
+				gotoChangePassword(null);
 				break;
 			case R.id.action_mam_prefs:
 				editMamPrefs();
@@ -602,6 +628,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 		return super.onOptionsItemSelected(item);
 	}
 
+	private void gotoChangePassword(String newPassword) {
+		final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
+		changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString());
+		if (newPassword != null) {
+			changePasswordIntent.putExtra("password", newPassword);
+		}
+		startActivity(changePasswordIntent);
+	}
+
 	private void renewCertificate() {
 		KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
 	}

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

@@ -8,6 +8,7 @@ import android.view.View;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import java.security.SecureRandom;
 
@@ -60,12 +61,14 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
 							account = new Account(jid, createPassword());
 							account.setOption(Account.OPTION_REGISTER, true);
 							account.setOption(Account.OPTION_DISABLED, true);
+							account.setOption(Account.OPTION_MAGIC_CREATE, true);
 							xmppConnectionService.createAccount(account);
 						}
 						Intent intent = new Intent(MagicCreateActivity.this, EditAccountActivity.class);
 						intent.putExtra("jid", account.getJid().toBareJid().toString());
 						intent.putExtra("init", true);
 						intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+						Toast.makeText(MagicCreateActivity.this, R.string.secure_password_generated, Toast.LENGTH_SHORT).show();
 						startActivity(intent);
 					} catch (InvalidJidException e) {
 						mUsername.setError(getString(R.string.invalid_username));

src/main/res/layout/activity_change_password.xml 🔗

@@ -2,23 +2,25 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:background="@color/grey50">
+                android:background="@color/grey200">
 
 	<ScrollView
 		android:layout_width="fill_parent"
 		android:layout_height="fill_parent"
 		android:layout_above="@+id/button_bar">
-
-		<LinearLayout
-			android:layout_width="match_parent"
-			android:layout_height="match_parent"
-			android:orientation="vertical"
-			android:layout_marginLeft="@dimen/activity_horizontal_margin"
-			android:layout_marginRight="@dimen/activity_horizontal_margin"
-			android:layout_marginTop="@dimen/activity_vertical_margin"
-			android:layout_marginBottom="@dimen/activity_vertical_margin">
+			<LinearLayout
+				android:layout_width="match_parent"
+				android:layout_height="wrap_content"
+				android:layout_marginLeft="@dimen/activity_horizontal_margin"
+				android:layout_marginRight="@dimen/activity_horizontal_margin"
+				android:layout_marginTop="@dimen/activity_vertical_margin"
+				android:layout_marginBottom="@dimen/activity_vertical_margin"
+				android:background="@drawable/infocard_border"
+				android:padding="@dimen/infocard_padding"
+				android:orientation="vertical">
 
 			<TextView
+				android:id="@+id/current_password_label"
 				android:layout_width="wrap_content"
 				android:layout_height="wrap_content"
 				android:text="@string/current_password"

src/main/res/values/strings.xml 🔗

@@ -635,4 +635,5 @@
 	<string name="presence_away">Away</string>
 	<string name="presence_xa">Not Available</string>
 	<string name="presence_dnd">Busy</string>
+	<string name="secure_password_generated">A secure password has been generated</string>
 </resources>