mirror of
https://github.com/status-im/syng-client.git
synced 2025-02-23 08:28:07 +00:00
Partially implemented multiple addresses per profile and profile password.
This commit is contained in:
parent
80656a219b
commit
36036c5568
@ -14,6 +14,7 @@ import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
@ -24,6 +25,8 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -39,12 +42,17 @@ public class BaseActivity extends AppCompatActivity {
|
||||
protected List<Profile> profiles;
|
||||
|
||||
Spinner spinner;
|
||||
SpinnerAdapter spinnerAdapter;
|
||||
|
||||
EditText search;
|
||||
ListView drawerList;
|
||||
|
||||
TextView settings;
|
||||
TextView profileManager;
|
||||
|
||||
Profile requestProfile;
|
||||
int currentPosition;
|
||||
|
||||
protected ArrayAdapter<String> drawerListAdapter;
|
||||
|
||||
@Override
|
||||
@ -130,21 +138,74 @@ public class BaseActivity extends AppCompatActivity {
|
||||
});
|
||||
}
|
||||
|
||||
protected void changeProfile(Profile profile) {
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
Syng application = (Syng)getApplication();
|
||||
List<String> privateKeys = profile.getPrivateKeys();
|
||||
application.ethereum.init(privateKeys);
|
||||
currentPosition = spinnerAdapter.getPosition(profile);
|
||||
}
|
||||
|
||||
protected void requestChangeProfile(Profile profile) {
|
||||
|
||||
requestProfile = profile;
|
||||
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)
|
||||
.contentColor(R.color.accent) // notice no 'res' postfix for literal color
|
||||
.dividerColorRes(R.color.accent)
|
||||
.backgroundColorRes(R.color.primary_dark)
|
||||
.positiveColorRes(R.color.accent)
|
||||
.negativeColorRes(R.color.accent)
|
||||
.widgetColorRes(R.color.accent)
|
||||
.callback(new MaterialDialog.ButtonCallback() {
|
||||
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
|
||||
View view = dialog.getCustomView();
|
||||
EditText passwordInput = (EditText) view.findViewById(R.id.passwordInput);
|
||||
if (requestProfile.decrypt(passwordInput.getText().toString())) {
|
||||
changeProfile(requestProfile);
|
||||
} else {
|
||||
dialog.hide();
|
||||
spinner.setSelection(currentPosition, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegative(MaterialDialog dialog) {
|
||||
|
||||
dialog.hide();
|
||||
spinner.setSelection(currentPosition, false);
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.show();
|
||||
}
|
||||
|
||||
public void initSpinner() {
|
||||
|
||||
profiles = ((Syng)getApplication()).preferenceManager.getProfiles();
|
||||
ArrayList<String> spinnerItems = new ArrayList<>();
|
||||
for (Profile profile: profiles) {
|
||||
spinnerItems.add(profile.getName());
|
||||
}
|
||||
spinner.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, spinnerItems.toArray(new String[spinnerItems.size()])));
|
||||
spinnerAdapter = new SpinnerAdapter(this, android.R.layout.simple_dropdown_item_1line, profiles);
|
||||
spinner.setAdapter(spinnerAdapter);
|
||||
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
//String item = (String) adapterView.getItemAtPosition(i);
|
||||
if (adapterView != null && adapterView.getChildAt(0) != null) {
|
||||
((TextView) adapterView.getChildAt(0)).setTextColor(Color.parseColor("#ffffff"));
|
||||
}
|
||||
Profile profile = spinnerAdapter.getItem(i);
|
||||
if (profile.getPasswordProtectedProfile()) {
|
||||
requestChangeProfile(profile);
|
||||
} else {
|
||||
changeProfile(profile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -230,4 +291,54 @@ public class BaseActivity extends AppCompatActivity {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
drawerToggle.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
public class SpinnerAdapter extends ArrayAdapter<Profile> {
|
||||
|
||||
private Context context;
|
||||
|
||||
private List<Profile> values;
|
||||
|
||||
public SpinnerAdapter(Context context, int textViewResourceId, List<Profile> values) {
|
||||
|
||||
super(context, textViewResourceId, values);
|
||||
this.context = context;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
|
||||
return values.size();
|
||||
}
|
||||
|
||||
public Profile getItem(int position){
|
||||
|
||||
return values.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position){
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
return getCustomView(position, convertView, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
return getCustomView(position, convertView, parent);
|
||||
}
|
||||
|
||||
public View getCustomView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
LayoutInflater inflater = getLayoutInflater();
|
||||
View row=inflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
|
||||
TextView label=(TextView)row.findViewById(android.R.id.text1);
|
||||
label.setText(spinnerAdapter.getItem(position).getName());
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,13 +48,14 @@ public class MainActivity extends BaseActivity implements ConnectorHandler {
|
||||
private static int CONSOLE_LENGTH = 10000;
|
||||
private static int CONSOLE_REFRESH = 1000;
|
||||
|
||||
static EthereumConnector ethereum = null;
|
||||
protected String handlerIdentifier = UUID.randomUUID().toString();
|
||||
|
||||
TextViewUpdater consoleUpdater = new TextViewUpdater();
|
||||
|
||||
static DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
|
||||
|
||||
private boolean isConnectorReady = false;
|
||||
|
||||
private class TextViewUpdater implements Runnable {
|
||||
|
||||
private String txt;
|
||||
@ -85,10 +86,8 @@ public class MainActivity extends BaseActivity implements ConnectorHandler {
|
||||
consoleText.setText(MainActivity.consoleLog);
|
||||
consoleText.setMovementMethod(new ScrollingMovementMethod());
|
||||
|
||||
if (ethereum == null) {
|
||||
ethereum = new EthereumConnector(this, EthereumService.class);
|
||||
ethereum.registerHandler(this);
|
||||
}
|
||||
Syng application = (Syng)getApplication();
|
||||
application.ethereum.registerHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,8 +96,8 @@ public class MainActivity extends BaseActivity implements ConnectorHandler {
|
||||
super.onPause();
|
||||
isPaused = true;
|
||||
timer.cancel();
|
||||
ethereum.removeListener(handlerIdentifier);
|
||||
ethereum.unbindService();
|
||||
Syng application = (Syng)getApplication();
|
||||
application.ethereum.removeListener(handlerIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -127,14 +126,16 @@ public class MainActivity extends BaseActivity implements ConnectorHandler {
|
||||
} catch (IllegalStateException e){
|
||||
android.util.Log.i("Damn", "resume error");
|
||||
}
|
||||
ethereum.bindService();
|
||||
if (isConnectorReady) {
|
||||
Syng application = (Syng)getApplication();
|
||||
application.ethereum.addListener(handlerIdentifier, EnumSet.allOf(EventFlag.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
|
||||
super.onDestroy();
|
||||
ethereum.unbindService();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -231,7 +232,9 @@ public class MainActivity extends BaseActivity implements ConnectorHandler {
|
||||
@Override
|
||||
public void onConnectorConnected() {
|
||||
|
||||
ethereum.addListener(handlerIdentifier, EnumSet.allOf(EventFlag.class));
|
||||
isConnectorReady = true;
|
||||
Syng application = (Syng)getApplication();
|
||||
application.ethereum.addListener(handlerIdentifier, EnumSet.allOf(EventFlag.class));
|
||||
//ethereum.connect(SystemProperties.CONFIG.activePeerIP(), SystemProperties.CONFIG.activePeerPort(), SystemProperties.CONFIG.activePeerNodeid());
|
||||
ethereum.startJsonRpc();
|
||||
}
|
||||
@ -239,6 +242,9 @@ public class MainActivity extends BaseActivity implements ConnectorHandler {
|
||||
@Override
|
||||
public void onConnectorDisconnected() {
|
||||
|
||||
isConnectorReady = false;
|
||||
Syng application = (Syng)getApplication();
|
||||
application.ethereum.removeListener(handlerIdentifier);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,8 +8,11 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import io.syng.entities.Profile;
|
||||
|
||||
|
||||
@ -37,9 +40,44 @@ public class ProfileManagerActivity extends BaseActivity implements OnFragmentIn
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
||||
Profile profile = addProfileFragment.getProfile();
|
||||
profileManagerFragment.addProfile(profile);
|
||||
hideAddProfile();
|
||||
final Profile profile = addProfileFragment.getProfile();
|
||||
if (profile.getPasswordProtectedProfile()) {
|
||||
new MaterialDialog.Builder(ProfileManagerActivity.this)
|
||||
.title(R.string.request_profile_password)
|
||||
.customView(R.layout.profile_password, true)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.contentColor(R.color.accent) // notice no 'res' postfix for literal color
|
||||
.dividerColorRes(R.color.accent)
|
||||
.backgroundColorRes(R.color.primary_dark)
|
||||
.positiveColorRes(R.color.accent)
|
||||
.negativeColorRes(R.color.accent)
|
||||
.widgetColorRes(R.color.accent)
|
||||
.callback(new MaterialDialog.ButtonCallback() {
|
||||
|
||||
@Override
|
||||
public void onPositive(MaterialDialog dialog) {
|
||||
|
||||
View view = dialog.getCustomView();
|
||||
EditText passwordInput = (EditText) view.findViewById(R.id.passwordInput);
|
||||
profile.encrypt(passwordInput.getText().toString());
|
||||
profileManagerFragment.addProfile(profile);
|
||||
hideAddProfile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegative(MaterialDialog dialog) {
|
||||
|
||||
dialog.hide();
|
||||
spinner.setSelection(currentPosition, false);
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.show();
|
||||
} else {
|
||||
profileManagerFragment.addProfile(profile);
|
||||
hideAddProfile();
|
||||
}
|
||||
}
|
||||
});
|
||||
addProfileLink = (TextView)findViewById(R.id.add_profile_link);
|
||||
|
@ -2,6 +2,8 @@ package io.syng;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import org.ethereum.android.service.EthereumConnector;
|
||||
|
||||
import io.syng.entities.PreferenceManager;
|
||||
|
||||
|
||||
@ -9,6 +11,8 @@ public class Syng extends android.support.multidex.MultiDexApplication {
|
||||
|
||||
public PreferenceManager preferenceManager;
|
||||
|
||||
public static EthereumConnector ethereum = null;
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
|
||||
@ -20,6 +24,10 @@ public class Syng extends android.support.multidex.MultiDexApplication {
|
||||
|
||||
super.onCreate();
|
||||
preferenceManager = new PreferenceManager(this);
|
||||
if (ethereum == null) {
|
||||
ethereum = new EthereumConnector(this, EthereumService.class);
|
||||
ethereum.bindService();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -27,5 +35,6 @@ public class Syng extends android.support.multidex.MultiDexApplication {
|
||||
|
||||
super.onTerminate();
|
||||
preferenceManager.close();
|
||||
ethereum.unbindService();
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
package io.syng.entities;
|
||||
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Profile implements Serializable {
|
||||
|
||||
protected String name;
|
||||
|
||||
protected String privateKey;
|
||||
protected List<String> privateKeys = new ArrayList<>();
|
||||
|
||||
/* "password protect profile" (encrypt the private keys) */
|
||||
protected boolean passwordProtectedProfile = false;
|
||||
@ -16,37 +20,49 @@ public class Profile implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected String passwordHash;
|
||||
|
||||
protected transient boolean isEncrypted = false;
|
||||
|
||||
public Profile() {
|
||||
|
||||
this.privateKey = createPrivateKey();
|
||||
this.privateKeys.add(createPrivateKey());
|
||||
}
|
||||
|
||||
public Profile(String privateKey) {
|
||||
|
||||
this.privateKey = privateKey;
|
||||
this.privateKeys.add(privateKey);
|
||||
}
|
||||
|
||||
public Profile(List<String> privateKeys) {
|
||||
|
||||
this.privateKeys = privateKeys;
|
||||
}
|
||||
|
||||
protected String createPrivateKey() {
|
||||
|
||||
return "";
|
||||
byte[] privateKey = HashUtil.sha3(HashUtil.randomPeerId());
|
||||
return Hex.toHexString(privateKey);
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
public List<String> getPrivateKeys() {
|
||||
|
||||
if (passwordProtectedProfile) {
|
||||
return decryptPrivateKey(privateKey, null);
|
||||
} else {
|
||||
return privateKey;
|
||||
}
|
||||
return privateKeys;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
public void setPrivateKeys(List<String> privateKeys) {
|
||||
|
||||
if (passwordProtectedProfile) {
|
||||
this.privateKey = encryptPrivateKey(privateKey, null);
|
||||
} else {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
this.privateKeys = privateKeys;
|
||||
}
|
||||
|
||||
public void addPrivateKey(String privateKey) {
|
||||
|
||||
this.privateKeys.add(privateKey);
|
||||
}
|
||||
|
||||
public void removePrivateKey(String privateKey) {
|
||||
|
||||
this.privateKeys.remove(privateKey);
|
||||
}
|
||||
|
||||
public List<Dapp> getDapps() {
|
||||
@ -77,9 +93,6 @@ public class Profile implements Serializable {
|
||||
public void setPasswordProtectedProfile(boolean passwordProtectedProfile) {
|
||||
|
||||
this.passwordProtectedProfile = passwordProtectedProfile;
|
||||
if (passwordProtectedProfile) {
|
||||
this.privateKey = encryptPrivateKey(privateKey, null);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@ -92,6 +105,40 @@ public class Profile implements Serializable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected void setPassword(String password) {
|
||||
|
||||
this.passwordHash = Hex.toHexString(HashUtil.sha3(password.getBytes()));
|
||||
}
|
||||
|
||||
public void encrypt(String password) {
|
||||
|
||||
if (!passwordProtectedProfile) {
|
||||
setPassword(password);
|
||||
List<String> encrypted = new ArrayList<>();
|
||||
for (String privateKey : this.privateKeys) {
|
||||
encrypted.add(encryptPrivateKey(privateKey, password));
|
||||
}
|
||||
this.privateKeys = encrypted;
|
||||
passwordProtectedProfile = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean decrypt(String password) {
|
||||
|
||||
if (passwordProtectedProfile) {
|
||||
if (passwordHash != Hex.toHexString(HashUtil.sha3(password.getBytes()))) {
|
||||
return false;
|
||||
}
|
||||
List<String> decrypted = new ArrayList<>();
|
||||
for (String privateKey : this.privateKeys) {
|
||||
decrypted.add(decryptPrivateKey(privateKey, password));
|
||||
}
|
||||
this.privateKeys = decrypted;
|
||||
passwordProtectedProfile = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected String encryptPrivateKey(String privateKey, String password) {
|
||||
|
||||
// TODO: Encrypt private key
|
||||
|
11
app/src/main/res/layout/profile_password.xml
Normal file
11
app/src/main/res/layout/profile_password.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/passwordInput"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:password="true"/>
|
||||
</LinearLayout>
|
@ -32,4 +32,7 @@
|
||||
<string name="create_new_account">Create new Account</string>
|
||||
<string name="import_account_from_file">Import account from file</string>
|
||||
<string name="import_account_from_string">Import account from string</string>
|
||||
|
||||
<string name="request_profile_password">Profile Password</string>
|
||||
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user