From fe040595dbaad6fa2ade4c94a5047104ae4a260f Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 22 Oct 2015 03:00:21 +0300 Subject: [PATCH 1/2] Implemented AES 256 bit encryption for profile private keys and changed encryption logic. --- .../java/io/syng/activity/BaseActivity.java | 89 +++++++------ .../java/io/syng/activity/LoginActivity.java | 28 +++- .../java/io/syng/app/SyngApplication.java | 7 +- app/src/main/java/io/syng/entity/Profile.java | 123 +++++++++++++----- .../fragment/profile/ProfileKeysFragment.java | 4 - .../main/java/io/syng/util/Encryption.java | 107 +++++++++++++++ .../main/java/io/syng/util/GeneralUtil.java | 36 ++++- .../java/io/syng/util/ProfileManager.java | 4 +- app/src/main/res/layout/wallet_import.xml | 10 +- 9 files changed, 315 insertions(+), 93 deletions(-) create mode 100644 app/src/main/java/io/syng/util/Encryption.java diff --git a/app/src/main/java/io/syng/activity/BaseActivity.java b/app/src/main/java/io/syng/activity/BaseActivity.java index 31e2fcc..a0c7aa4 100644 --- a/app/src/main/java/io/syng/activity/BaseActivity.java +++ b/app/src/main/java/io/syng/activity/BaseActivity.java @@ -230,28 +230,30 @@ public abstract class BaseActivity extends AppCompatActivity implements } private void requestChangeProfile(final Profile profile) { - Dialog dialog = new MaterialDialog.Builder(BaseActivity.this) - .title(R.string.request_profile_password) - .customView(R.layout.profile_password, true) - .positiveText(R.string.ok) - .negativeText(R.string.cancel) - .callback(new MaterialDialog.ButtonCallback() { - @SuppressWarnings("ConstantConditions") - @Override - public void onPositive(MaterialDialog dialog) { - View view = dialog.getCustomView(); - EditText password = (EditText) view.findViewById(R.id.et_pass); - if (profile.checkPassword(password.getText().toString())) { - ProfileManager.setCurrentProfile(profile); - flipDrawer(); - } else { - Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show(); - } - } - }) - .show(); - EditText name = (EditText) dialog.findViewById(R.id.et_pass); - GeneralUtil.showKeyBoard(name, this); + + GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, new MaterialDialog.ButtonCallback() { + @SuppressWarnings("ConstantConditions") + @Override + public void onPositive(MaterialDialog dialog) { + View view = dialog.getCustomView(); + EditText passwordText = (EditText) view.findViewById(R.id.et_pass); + String password = passwordText.getText().toString(); + if (profile.checkPassword(password)) { + ProfileManager.setCurrentProfile(profile, password); + flipDrawer(); + dialog.dismiss(); + } else { + Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show(); + } + + } + + @Override + public void onNegative(MaterialDialog dialog) { + dialog.dismiss(); + } + + }); } private void updateCurrentProfileName() { @@ -404,30 +406,27 @@ public abstract class BaseActivity extends AppCompatActivity implements ProfileDialogFragment dialogFragment = ProfileDialogFragment.newInstance(profile); dialogFragment.show(getSupportFragmentManager(), "profile_dialog"); } else { - Dialog dialog = new MaterialDialog.Builder(BaseActivity.this) - .title(R.string.request_profile_password) - .customView(R.layout.profile_password, true) - .positiveText(R.string.ok) - .negativeText(R.string.cancel) - .callback(new MaterialDialog.ButtonCallback() { - @SuppressWarnings("ConstantConditions") - @Override - public void onPositive(MaterialDialog dialog) { - View view = dialog.getCustomView(); - EditText password = (EditText) view.findViewById(R.id.et_pass); - if (profile.checkPassword(password.getText().toString())) { - ProfileDialogFragment dialogFragment = ProfileDialogFragment.newInstance(profile); - dialogFragment.show(getSupportFragmentManager(), "profile_dialog"); - } else { - Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show(); - } - } - }) - .show(); - EditText name = (EditText) dialog.findViewById(R.id.et_pass); - GeneralUtil.showKeyBoard(name, this); - } + GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + View view = dialog.getCustomView(); + EditText password = (EditText) view.findViewById(R.id.et_pass); + if (profile.checkPassword(password.getText().toString())) { + dialog.dismiss(); + ProfileDialogFragment dialogFragment = ProfileDialogFragment.newInstance(profile); + dialogFragment.show(getSupportFragmentManager(), "profile_dialog"); + } else { + Toast.makeText(BaseActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onNegative(MaterialDialog dialog) { + dialog.dismiss(); + } + }); + } } @Override diff --git a/app/src/main/java/io/syng/activity/LoginActivity.java b/app/src/main/java/io/syng/activity/LoginActivity.java index 7fad3c6..8fd7d6c 100644 --- a/app/src/main/java/io/syng/activity/LoginActivity.java +++ b/app/src/main/java/io/syng/activity/LoginActivity.java @@ -12,6 +12,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; +import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast; @@ -44,9 +45,8 @@ public class LoginActivity extends AppCompatActivity { if (PrefsUtil.isFirstLaunch()) { createAndSetProfile(); } else { - startNextActivity(); + loginWallet(); } - } private void startNextActivity() { @@ -76,7 +76,31 @@ public class LoginActivity extends AppCompatActivity { LoginActivity.this.finish(); dialog.dismiss(); } + }); + } + private void loginWallet() { + GeneralUtil.showProfilePasswordRequestDialog(LoginActivity.this, new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + View view = dialog.getCustomView(); + EditText passwordText = (EditText) view.findViewById(R.id.et_pass); + Profile profile = ProfileManager.getCurrentProfile(); + String password = passwordText.getText().toString(); + if (profile.checkPassword(password)) { + dialog.dismiss(); + ProfileManager.setCurrentProfile(profile, password); + startNextActivity(); + } else { + Toast.makeText(LoginActivity.this, "Password is not correct", Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onNegative(MaterialDialog dialog) { + LoginActivity.this.finish(); + dialog.dismiss(); + } }); } diff --git a/app/src/main/java/io/syng/app/SyngApplication.java b/app/src/main/java/io/syng/app/SyngApplication.java index 2acadcd..e2cd23b 100644 --- a/app/src/main/java/io/syng/app/SyngApplication.java +++ b/app/src/main/java/io/syng/app/SyngApplication.java @@ -33,6 +33,7 @@ import org.ethereum.net.p2p.HelloMessage; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; import java.util.EnumSet; import java.util.UUID; @@ -57,6 +58,8 @@ public class SyngApplication extends MultiDexApplication implements ConnectorHan private boolean isRpcConnection = true; + public boolean isEthereumConnected = false; + private String mHandlerIdentifier = UUID.randomUUID().toString(); @Override @@ -92,8 +95,9 @@ public class SyngApplication extends MultiDexApplication implements ConnectorHan @Override public void onConnectorConnected() { System.out.println("Connector connected"); + isEthereumConnected = true; SyngApplication.sEthereumConnector.addListener(mHandlerIdentifier, EnumSet.allOf(EventFlag.class)); - sEthereumConnector.init(ProfileManager.getCurrentProfile().getPrivateKeys()); + sEthereumConnector.init(new ArrayList()); sEthereumConnector.startJsonRpc(); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); String rpcServer = sharedPref.getString(getString(R.string.pref_json_rpc_server_key), "http://rpc0.syng.io:8545/"); @@ -103,6 +107,7 @@ public class SyngApplication extends MultiDexApplication implements ConnectorHan @Override public void onConnectorDisconnected() { System.out.println("Connector Disconnected"); + isEthereumConnected = false; } @Override diff --git a/app/src/main/java/io/syng/entity/Profile.java b/app/src/main/java/io/syng/entity/Profile.java index 31b695a..8f644c5 100644 --- a/app/src/main/java/io/syng/entity/Profile.java +++ b/app/src/main/java/io/syng/entity/Profile.java @@ -8,22 +8,24 @@ package io.syng.entity; +import android.util.Log; + import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; import org.ethereum.wallet.EtherSaleWallet; import org.ethereum.wallet.EtherSaleWalletDecoder; import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.spongycastle.util.encoders.Hex; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import io.syng.util.Encryption; + public class Profile implements Serializable { - private static final Logger logger = LoggerFactory.getLogger("Profile"); + private static final String TAG = "Profile"; protected String name; @@ -31,6 +33,8 @@ public class Profile implements Serializable { protected List privateKeys = new ArrayList<>(); + protected List publicKeys = new ArrayList<>(); + /* "password protect profile" (encrypt the private keys) */ protected boolean passwordProtectedProfile; @@ -42,18 +46,21 @@ public class Profile implements Serializable { protected transient boolean isEncrypted; + public Profile() { - this.privateKeys.add(createPrivateKey()); + addPrivateKey(createPrivateKey(), null); addDefaultApps(); } public Profile(String privateKey) { - this.privateKeys.add(privateKey); + addPrivateKey(privateKey, null); addDefaultApps(); } public Profile(List privateKeys) { - this.privateKeys = privateKeys; + for (String privateKey: privateKeys) { + addPrivateKey(privateKey, null); + } addDefaultApps(); } @@ -79,30 +86,53 @@ public class Profile implements Serializable { return Hex.toHexString(privateKey); } - public List getPrivateKeys() { - return privateKeys; + public List getPrivateKeys(String password) { + List keys = new ArrayList<>(); + + for (String privateKey: privateKeys) { + String key = passwordProtectedProfile ? decryptPrivateKey(privateKey, password) : privateKey; + keys.add(key); + } + return keys; } public List getAddresses() { + return publicKeys; + } - List addresses = new ArrayList<>(); - for (String privateKey : privateKeys) { - ECKey key = ECKey.fromPrivate(Hex.decode(privateKey)); - addresses.add(Hex.toHexString(key.getAddress())); + public void addPrivateKeys(List privateKeys, String password) { + for (String privateKey: privateKeys) { + addPrivateKey(privateKey, password); } - return addresses; } - public void setPrivateKeys(List privateKeys) { - this.privateKeys = privateKeys; + protected String getPublicKey(String privateKey) { + ECKey ecKey = ECKey.fromPrivate(Hex.decode(privateKey)); + return Hex.toHexString(ecKey.getAddress()); } - public void addPrivateKey(String privateKey) { - this.privateKeys.add(privateKey); + public boolean addPrivateKey(String privateKey, String password) { + + if (password != null && passwordProtectedProfile) { + if (!checkPassword(password)) { + return false; + } + this.privateKeys.add(encryptPrivateKey(privateKey, password)); + } else { + this.privateKeys.add(privateKey); + } + this.publicKeys.add(getPublicKey(privateKey)); + return true; + } + + private String hash(String text) { + return Hex.toHexString(HashUtil.sha3(text.getBytes())); } public void removePrivateKey(String privateKey) { + this.privateKeys.remove(privateKey); + this.publicKeys.remove(getPublicKey(privateKey)); } public List getDapps() { @@ -155,20 +185,23 @@ public class Profile implements Serializable { } public void setPassword(String password) { - this.passwordHash = Hex.toHexString(HashUtil.sha3(password.getBytes())); + if (!passwordProtectedProfile) { + this.passwordHash = hash(password); + this.encrypt(password); + } } public boolean checkPassword(String password) { - return passwordHash.equals(Hex.toHexString(HashUtil.sha3(password.getBytes()))); + return passwordHash.equals(hash(password)); } public void encrypt(String password) { if (!passwordProtectedProfile) { - setPassword(password); List encrypted = new ArrayList<>(); for (String privateKey : this.privateKeys) { encrypted.add(encryptPrivateKey(privateKey, password)); } + this.privateKeys.clear(); this.privateKeys = encrypted; passwordProtectedProfile = true; } @@ -176,7 +209,7 @@ public class Profile implements Serializable { public boolean decrypt(String password) { if (passwordProtectedProfile) { - if (!passwordHash.equals(Hex.toHexString(HashUtil.sha3(password.getBytes())))) { + if (!checkPassword(password)) { return false; } List decrypted = new ArrayList<>(); @@ -190,16 +223,22 @@ public class Profile implements Serializable { } protected String encryptPrivateKey(String privateKey, String password) { - // TODO: Encrypt private key - return privateKey; + String encryptedKey = Encryption.encrypt(privateKey, password); + if (encryptedKey == null) { + Log.w(TAG, "Could not encrypt private key"); + } + return encryptedKey; } protected String decryptPrivateKey(String privateKey, String password) { - // TODO: Decrypt private key - return privateKey; + String decryptedKey = Encryption.decrypt(privateKey, password); + if (decryptedKey == null) { + Log.w(TAG, "Could not decrypt private key"); + } + return decryptedKey; } - public boolean importWallet(String jsonWallet, String password) { + public boolean importWallet(String jsonWallet, String importPassword, String currentPassword) { try { JSONObject json = new JSONObject(jsonWallet); byte[] privateKey = null; @@ -210,35 +249,51 @@ public class Profile implements Serializable { wallet.setEmail(json.getString("email")); wallet.setBtcaddr(json.getString("btcaddr")); EtherSaleWalletDecoder decoder = new EtherSaleWalletDecoder(wallet); - privateKey = decoder.getPrivateKey(password); + privateKey = decoder.getPrivateKey(importPassword); } else if (json.has("Crypto")) { wallet.setEncseed(json.getJSONObject("Crypto").getJSONObject("cipherparams").getString("iv") + json.getJSONObject("Crypto").getString("ciphertext")); wallet.setEthaddr(json.getString("address")); EtherSaleWalletDecoder decoder = new EtherSaleWalletDecoder(wallet); - privateKey = decoder.getPrivateKey(password); + privateKey = decoder.getPrivateKey(importPassword); } if (privateKey == null) { - logger.warn("Invalid json wallet file."); + Log.w(TAG, "Invalid json wallet file."); return false; } ECKey key = ECKey.fromPrivate(privateKey); String address = Hex.toHexString(key.getAddress()); if (address.equals(wallet.getEthaddr())) { - privateKeys.add(Hex.toHexString(privateKey)); + String keyToAdd = Hex.toHexString(privateKey); + if (passwordProtectedProfile) { + addPrivateKey(keyToAdd, currentPassword); + } else { + addPrivateKey(keyToAdd, null); + } + this.publicKeys.add(getPublicKey(keyToAdd)); } else { - logger.warn("Invalid wallet password."); + Log.w(TAG, "Invalid wallet password."); return false; } } catch (Exception e) { - logger.error("Error importing wallet.", e); + Log.e(TAG, "Error importing wallet: " + e.getMessage()); return false; } return true; } - public void importPrivateKey(String privateKey, String password) { - privateKeys.add(decryptPrivateKey(privateKey, password)); + public boolean importPrivateKey(String privateKey, String importedKeyPassword, String walletPassword) { + String decryptedKey = importedKeyPassword == null || importedKeyPassword == "" ? privateKey : decryptPrivateKey(privateKey, importedKeyPassword); + if (passwordProtectedProfile) { + if (checkPassword(walletPassword)) { + addPrivateKey(decryptedKey, walletPassword); + } else { + return false; + } + } else { + addPrivateKey(decryptedKey, null); + } + return true; } @Override diff --git a/app/src/main/java/io/syng/fragment/profile/ProfileKeysFragment.java b/app/src/main/java/io/syng/fragment/profile/ProfileKeysFragment.java index a0edc31..3ecc1fe 100644 --- a/app/src/main/java/io/syng/fragment/profile/ProfileKeysFragment.java +++ b/app/src/main/java/io/syng/fragment/profile/ProfileKeysFragment.java @@ -51,10 +51,6 @@ public class ProfileKeysFragment extends Fragment { View view = inflater.inflate(R.layout.fragment_profile_keys, container, false); Profile profile = ProfileManager.getProfileById(mProfileId); - if (profile != null) { - profile.getPrivateKeys(); - } - mRecyclerView = (RecyclerView) view.findViewById(R.id.rv_profile_keys); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(layoutManager); diff --git a/app/src/main/java/io/syng/util/Encryption.java b/app/src/main/java/io/syng/util/Encryption.java new file mode 100644 index 0000000..1312e88 --- /dev/null +++ b/app/src/main/java/io/syng/util/Encryption.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015 Jarrad Hope + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package io.syng.util; + +import android.util.Base64; +import android.util.Log; + +import java.security.SecureRandom; +import java.security.spec.KeySpec; +import java.util.regex.Pattern; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +public class Encryption { + + private static final String TAG = "Encryption"; + + private static SecureRandom random = new SecureRandom(); + private static String delimiter = "}"; + private static int keyLength = 256; + private static int saltLength = keyLength / 8; + private static int iterationCount = 20000; + + public static String encrypt(String text, String password) { + + Log.d(TAG, "Encrypting: " + text); + String encryptedText = ""; + byte[] salt = generateSalt(saltLength); + SecretKey key = generateKey(password, salt); + if (key != null) { + try { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + byte[] iv = new byte[cipher.getBlockSize()]; + random.nextBytes(iv); + IvParameterSpec ivParams = new IvParameterSpec(iv); + cipher.init(Cipher.ENCRYPT_MODE, key, ivParams); + byte[] encryptedKey = cipher.doFinal(text.getBytes("UTF-8")); + + encryptedText = Base64.encodeToString(salt, Base64.NO_WRAP); + encryptedText += delimiter + Base64.encodeToString(iv, Base64.NO_WRAP); + encryptedText += delimiter + Base64.encodeToString(encryptedKey, Base64.NO_WRAP); + Log.d(TAG, "Encrypted: " + encryptedText); + return encryptedText; + } catch (Exception e) { + Log.e(TAG, "encrypt(): " + e.toString()); + } + } + return null; + } + + private static byte[] generateSalt(int saltLength) { + + byte[] salt = new byte[saltLength]; + random.nextBytes(salt); + return salt; + } + + private static SecretKey generateKey(String password, byte[] salt) { + try { + KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded(); + return new SecretKeySpec(keyBytes, "AES"); + } catch (Exception e) { + Log.e(TAG, "generateKey(): " + e.toString()); + } + return null; + } + + public static String decrypt(String encryptedText, String password) { + + Log.d(TAG, "Decrypting: " + encryptedText); + String[] parts = encryptedText.split(Pattern.quote(delimiter)); + byte[] salt = Base64.decode(parts[0], Base64.NO_WRAP); + byte[] iv = Base64.decode(parts[1], Base64.NO_WRAP); + byte[] cipherBytes = Base64.decode(parts[2], Base64.NO_WRAP); + + SecretKey key = generateKey(password, salt); + if (key != null) { + try { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec ivParams = new IvParameterSpec(iv); + cipher.init(Cipher.DECRYPT_MODE, key, ivParams); + byte[] decrypted = cipher.doFinal(cipherBytes); + String decryptedText = new String(decrypted, "UTF-8"); + Log.d(TAG, "Decrypted: " + decryptedText); + return decryptedText; + } catch (Exception e) { + Log.e(TAG, "decrypt(): " + e.toString()); + } + } + + return null; + } + +} diff --git a/app/src/main/java/io/syng/util/GeneralUtil.java b/app/src/main/java/io/syng/util/GeneralUtil.java index 1e6aacf..f61a57f 100644 --- a/app/src/main/java/io/syng/util/GeneralUtil.java +++ b/app/src/main/java/io/syng/util/GeneralUtil.java @@ -112,7 +112,7 @@ public final class GeneralUtil { profile.setName(name.getText().toString()); profile.setPassword(pass1String); ProfileManager.addProfile(profile); - ProfileManager.setCurrentProfile(profile); + ProfileManager.setCurrentProfile(profile, pass1String); GeneralUtil.hideKeyBoard(name, context); GeneralUtil.hideKeyBoard(pass1, context); GeneralUtil.hideKeyBoard(pass2, context); @@ -150,6 +150,32 @@ public final class GeneralUtil { GeneralUtil.showKeyBoard(name, context); } + public static void showProfilePasswordRequestDialog(final Context context, MaterialDialog.ButtonCallback callback) { + + if (callback == null) { + callback = new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + dialog.dismiss(); + } + + @Override + public void onNegative(MaterialDialog dialog) { + dialog.dismiss(); + } + }; + } + MaterialDialog dialog = new MaterialDialog.Builder(context) + .title(R.string.request_profile_password) + .positiveText(R.string.ok) + .negativeText(R.string.cancel) + .customView(R.layout.profile_password, true) + .callback(callback) + .show(); + EditText name = (EditText) dialog.findViewById(R.id.et_pass); + GeneralUtil.showKeyBoard(name, context); + } + public static void showDAppEditDialog(final Dapp dapp, final Context context) { MaterialDialog dialog = new MaterialDialog.Builder(context) .title("Edit") @@ -256,8 +282,10 @@ public final class GeneralUtil { RadioButton importJsonRadio = (RadioButton) dialog.findViewById(R.id.radio_import_json); EditText importPathEdit = (EditText) dialog.findViewById(R.id.wallet_import_path); EditText walletPasswordEdit = (EditText) dialog.findViewById(R.id.wallet_password); + EditText currentWalletPasswordEdit = (EditText) dialog.findViewById(R.id.current_wallet_password); String importPath = importPathEdit.getText().toString(); String password = walletPasswordEdit.getText().toString(); + String currentPassword = currentWalletPasswordEdit.getText().toString(); String fileContents = null; try { File walletFile = new File(importPath); @@ -281,15 +309,15 @@ public final class GeneralUtil { } if (importJsonRadio.isChecked()) { Profile profile = ProfileManager.getCurrentProfile(); - if (profile.importWallet(fileContents, password)) { + if (profile.importWallet(fileContents, password, currentPassword)) { ProfileManager.updateProfile(profile); - ProfileManager.setCurrentProfile(profile); + ProfileManager.setCurrentProfile(profile, currentPassword); } else { Toast.makeText(context, R.string.invalid_wallet_password, Toast.LENGTH_SHORT).show(); } } else { Profile profile = ProfileManager.getCurrentProfile(); - profile.importPrivateKey(fileContents, password); + profile.importPrivateKey(fileContents, password, currentPassword); ProfileManager.updateProfile(profile); } } diff --git a/app/src/main/java/io/syng/util/ProfileManager.java b/app/src/main/java/io/syng/util/ProfileManager.java index f1a782f..4f4726f 100644 --- a/app/src/main/java/io/syng/util/ProfileManager.java +++ b/app/src/main/java/io/syng/util/ProfileManager.java @@ -110,8 +110,8 @@ public final class ProfileManager { return new Profile(); } - public static void setCurrentProfile(Profile profile) { - List privateKeys = profile.getPrivateKeys(); + public static void setCurrentProfile(Profile profile, String password) { + List privateKeys = profile.getPrivateKeys(password); SyngApplication.sEthereumConnector.init(privateKeys); PrefsUtil.setCurrentProfileId(profile.getId()); notifyListener(); diff --git a/app/src/main/res/layout/wallet_import.xml b/app/src/main/res/layout/wallet_import.xml index b6bc0c5..52bf3cc 100644 --- a/app/src/main/res/layout/wallet_import.xml +++ b/app/src/main/res/layout/wallet_import.xml @@ -38,7 +38,15 @@ android:id="@+id/wallet_password" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:hint="Password" + android:hint="Import Password" + android:singleLine="true" + android:textColor="@color/accent"/> + + \ No newline at end of file From e35069a39fc3e82dd61dcfe64ffdffdddf7506e1 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 22 Oct 2015 13:02:19 +0200 Subject: [PATCH 2/2] Disable autodissmiss on password dialog. Add profile name to password dialog. --- app/src/main/java/io/syng/activity/BaseActivity.java | 4 ++-- app/src/main/java/io/syng/activity/LoginActivity.java | 4 ++-- app/src/main/java/io/syng/util/GeneralUtil.java | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/syng/activity/BaseActivity.java b/app/src/main/java/io/syng/activity/BaseActivity.java index a0c7aa4..a66ad9d 100644 --- a/app/src/main/java/io/syng/activity/BaseActivity.java +++ b/app/src/main/java/io/syng/activity/BaseActivity.java @@ -231,7 +231,7 @@ public abstract class BaseActivity extends AppCompatActivity implements private void requestChangeProfile(final Profile profile) { - GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, new MaterialDialog.ButtonCallback() { + GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, profile.getName(), new MaterialDialog.ButtonCallback() { @SuppressWarnings("ConstantConditions") @Override public void onPositive(MaterialDialog dialog) { @@ -406,7 +406,7 @@ public abstract class BaseActivity extends AppCompatActivity implements ProfileDialogFragment dialogFragment = ProfileDialogFragment.newInstance(profile); dialogFragment.show(getSupportFragmentManager(), "profile_dialog"); } else { - GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, new MaterialDialog.ButtonCallback() { + GeneralUtil.showProfilePasswordRequestDialog(BaseActivity.this, profile.getName(), new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog dialog) { diff --git a/app/src/main/java/io/syng/activity/LoginActivity.java b/app/src/main/java/io/syng/activity/LoginActivity.java index 8fd7d6c..2c5a867 100644 --- a/app/src/main/java/io/syng/activity/LoginActivity.java +++ b/app/src/main/java/io/syng/activity/LoginActivity.java @@ -80,12 +80,12 @@ public class LoginActivity extends AppCompatActivity { } private void loginWallet() { - GeneralUtil.showProfilePasswordRequestDialog(LoginActivity.this, new MaterialDialog.ButtonCallback() { + final Profile profile = ProfileManager.getCurrentProfile(); + GeneralUtil.showProfilePasswordRequestDialog(LoginActivity.this, profile.getName(), new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog dialog) { View view = dialog.getCustomView(); EditText passwordText = (EditText) view.findViewById(R.id.et_pass); - Profile profile = ProfileManager.getCurrentProfile(); String password = passwordText.getText().toString(); if (profile.checkPassword(password)) { dialog.dismiss(); diff --git a/app/src/main/java/io/syng/util/GeneralUtil.java b/app/src/main/java/io/syng/util/GeneralUtil.java index f61a57f..6fa389b 100644 --- a/app/src/main/java/io/syng/util/GeneralUtil.java +++ b/app/src/main/java/io/syng/util/GeneralUtil.java @@ -150,7 +150,7 @@ public final class GeneralUtil { GeneralUtil.showKeyBoard(name, context); } - public static void showProfilePasswordRequestDialog(final Context context, MaterialDialog.ButtonCallback callback) { + public static void showProfilePasswordRequestDialog(final Context context, String profileName, MaterialDialog.ButtonCallback callback) { if (callback == null) { callback = new MaterialDialog.ButtonCallback() { @@ -166,11 +166,12 @@ public final class GeneralUtil { }; } MaterialDialog dialog = new MaterialDialog.Builder(context) - .title(R.string.request_profile_password) + .title((profileName != null ? profileName + " " : "") + context.getResources().getString(R.string.request_profile_password)) .positiveText(R.string.ok) .negativeText(R.string.cancel) .customView(R.layout.profile_password, true) .callback(callback) + .autoDismiss(false) .show(); EditText name = (EditText) dialog.findViewById(R.id.et_pass); GeneralUtil.showKeyBoard(name, context);