mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-10 05:40:51 +02:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b1d91e2671 | ||
![]() |
271cd2d4a8 | ||
![]() |
22c5a543db | ||
![]() |
cd986860c5 | ||
![]() |
0cf5981eae | ||
![]() |
e109df34f0 | ||
![]() |
5a7aa6cc77 | ||
![]() |
f50629ff81 | ||
![]() |
cb12d64e5f | ||
![]() |
a8f08fb9b9 |
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 91
|
versionCode 94
|
||||||
versionName "1.5.1 'CrAzY Nacho'"
|
versionName "1.5.4 'CrAzY Nacho'"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
@@ -697,16 +697,26 @@ Java_com_m2049r_xmrwallet_model_Wallet_isSynchronized(JNIEnv *env, jobject insta
|
|||||||
|
|
||||||
//void cn_slow_hash(const void *data, size_t length, char *hash); // from crypto/hash-ops.h
|
//void cn_slow_hash(const void *data, size_t length, char *hash); // from crypto/hash-ops.h
|
||||||
JNIEXPORT jbyteArray JNICALL
|
JNIEXPORT jbyteArray JNICALL
|
||||||
Java_com_m2049r_xmrwallet_util_KeyStoreHelper_cnSlowHash(JNIEnv *env, jobject clazz,
|
Java_com_m2049r_xmrwallet_util_KeyStoreHelper_slowHash(JNIEnv *env, jobject clazz,
|
||||||
jbyteArray data) {
|
jbyteArray data, jint brokenVariant) {
|
||||||
|
char hash[HASH_SIZE];
|
||||||
|
jsize size = env->GetArrayLength(data);
|
||||||
|
if ((brokenVariant > 0) && (size < 200 /*sizeof(union hash_state)*/)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
jbyte *buffer = env->GetByteArrayElements(data, NULL);
|
jbyte *buffer = env->GetByteArrayElements(data, NULL);
|
||||||
jsize size = env->GetArrayLength(data);
|
switch (brokenVariant) {
|
||||||
char hash[HASH_SIZE];
|
case 1:
|
||||||
cn_slow_hash(buffer, (size_t) size, hash);
|
slow_hash_broken(buffer, hash, 1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
slow_hash_broken(buffer, hash, 0);
|
||||||
|
break;
|
||||||
|
default: // not broken
|
||||||
|
slow_hash(buffer, (size_t) size, hash);
|
||||||
|
}
|
||||||
env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); // do not update java byte[]
|
env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); // do not update java byte[]
|
||||||
|
|
||||||
jbyteArray result = env->NewByteArray(HASH_SIZE);
|
jbyteArray result = env->NewByteArray(HASH_SIZE);
|
||||||
env->SetByteArrayRegion(result, 0, HASH_SIZE, (jbyte *) hash);
|
env->SetByteArrayRegion(result, 0, HASH_SIZE, (jbyte *) hash);
|
||||||
return result;
|
return result;
|
||||||
@@ -757,8 +767,6 @@ Java_com_m2049r_xmrwallet_model_Wallet_isAddressValid(JNIEnv *env, jobject clazz
|
|||||||
return static_cast<jboolean>(isValid);
|
return static_cast<jboolean>(isValid);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO static static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error);
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_Wallet_getPaymentIdFromAddress(JNIEnv *env, jobject clazz,
|
Java_com_m2049r_xmrwallet_model_Wallet_getPaymentIdFromAddress(JNIEnv *env, jobject clazz,
|
||||||
jstring address,
|
jstring address,
|
||||||
|
@@ -60,7 +60,15 @@ enum {
|
|||||||
HASH_DATA_AREA = 136
|
HASH_DATA_AREA = 136
|
||||||
};
|
};
|
||||||
|
|
||||||
void cn_slow_hash(const void *data, size_t length, char *hash);
|
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed);
|
||||||
|
|
||||||
|
inline void slow_hash(const void *data, const size_t length, char *hash) {
|
||||||
|
cn_slow_hash(data, length, hash, 0 /* variant */, 0/*prehashed*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void slow_hash_broken(const void *data, char *hash, int variant) {
|
||||||
|
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -53,7 +53,6 @@ import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
|||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -103,10 +102,10 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
bAccept = (Button) view.findViewById(R.id.bAccept);
|
bAccept = (Button) view.findViewById(R.id.bAccept);
|
||||||
|
|
||||||
boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
|
boolean allowCopy = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
|
||||||
tvWalletMnemonic.setTextIsSelectable(testnet);
|
tvWalletMnemonic.setTextIsSelectable(allowCopy);
|
||||||
tvWalletSpendKey.setTextIsSelectable(testnet);
|
tvWalletSpendKey.setTextIsSelectable(allowCopy);
|
||||||
tvWalletPassword.setTextIsSelectable(testnet);
|
tvWalletPassword.setTextIsSelectable(allowCopy);
|
||||||
|
|
||||||
bAccept.setOnClickListener(new View.OnClickListener() {
|
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -392,19 +391,19 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(String... params) {
|
protected Boolean doInBackground(String... params) {
|
||||||
if (params.length != 4) return false;
|
if (params.length != 2) return false;
|
||||||
File walletFile = Helper.getWalletFile(getActivity(), params[0]);
|
final String userPassword = params[0];
|
||||||
String oldPassword = params[1];
|
final boolean fingerPassValid = Boolean.valueOf(params[1]);
|
||||||
String userPassword = params[2];
|
|
||||||
boolean fingerprintAuthAllowed = Boolean.valueOf(params[3]);
|
|
||||||
newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword);
|
newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword);
|
||||||
boolean success = changeWalletPassword(newPassword);
|
final boolean success = changeWalletPassword(newPassword);
|
||||||
if (success) {
|
if (success) {
|
||||||
if (fingerprintAuthAllowed) {
|
Context ctx = getActivity();
|
||||||
KeyStoreHelper.saveWalletUserPass(getActivity(), walletName, userPassword);
|
if (ctx != null)
|
||||||
} else {
|
if (fingerPassValid) {
|
||||||
KeyStoreHelper.removeWalletUserPass(getActivity(), walletName);
|
KeyStoreHelper.saveWalletUserPass(ctx, walletName, userPassword);
|
||||||
}
|
} else {
|
||||||
|
KeyStoreHelper.removeWalletUserPass(ctx, walletName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@@ -412,7 +411,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Boolean result) {
|
protected void onPostExecute(Boolean result) {
|
||||||
super.onPostExecute(result);
|
super.onPostExecute(result);
|
||||||
if (getActivity().isDestroyed()) {
|
if ((getActivity() == null) || getActivity().isDestroyed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (progressCallback != null)
|
if (progressCallback != null)
|
||||||
@@ -467,11 +466,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
swFingerprintAllowed.setChecked(FingerprintHelper.isFingerPassValid(getActivity(), walletName));
|
||||||
swFingerprintAllowed.setChecked(FingerprintHelper.isFingerprintAuthAllowed(walletName));
|
|
||||||
} catch (KeyStoreException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
etPasswordA.getEditText().addTextChangedListener(new TextWatcher() {
|
etPasswordA.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
@@ -547,7 +542,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||||
} else if (newPasswordA.equals(newPasswordB)) {
|
} else if (newPasswordA.equals(newPasswordB)) {
|
||||||
new AsyncChangePassword().execute(walletName, getPassword(), newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||||
Helper.hideKeyboardAlways(getActivity());
|
Helper.hideKeyboardAlways(getActivity());
|
||||||
openDialog.dismiss();
|
openDialog.dismiss();
|
||||||
openDialog = null;
|
openDialog = null;
|
||||||
@@ -569,7 +564,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||||
} else if (newPasswordA.equals(newPasswordB)) {
|
} else if (newPasswordA.equals(newPasswordB)) {
|
||||||
new AsyncChangePassword().execute(walletName, getPassword(), newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||||
Helper.hideKeyboardAlways(getActivity());
|
Helper.hideKeyboardAlways(getActivity());
|
||||||
openDialog.dismiss();
|
openDialog.dismiss();
|
||||||
openDialog = null;
|
openDialog = null;
|
||||||
|
@@ -50,7 +50,6 @@ import com.m2049r.xmrwallet.model.NetworkType;
|
|||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.FingerprintHelper;
|
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
@@ -63,7 +62,6 @@ import java.io.IOException;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
@@ -229,17 +227,20 @@ public class LoginActivity extends SecureActivity
|
|||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(String... params) {
|
protected Boolean doInBackground(String... params) {
|
||||||
if (params.length != 2) return false;
|
if (params.length != 2) return false;
|
||||||
File walletFile = Helper.getWalletFile(LoginActivity.this, params[0]);
|
String oldName = params[0];
|
||||||
String newName = params[1];
|
String newName = params[1];
|
||||||
|
File walletFile = Helper.getWalletFile(LoginActivity.this, oldName);
|
||||||
boolean success = renameWallet(walletFile, newName);
|
boolean success = renameWallet(walletFile, newName);
|
||||||
try {
|
try {
|
||||||
if (success && FingerprintHelper.isFingerprintAuthAllowed(params[0])) {
|
if (success) {
|
||||||
String savedPass = KeyStoreHelper.loadWalletUserPass(LoginActivity.this, params[0]);
|
String savedPass = KeyStoreHelper.loadWalletUserPass(LoginActivity.this, oldName);
|
||||||
KeyStoreHelper.saveWalletUserPass(LoginActivity.this, newName, savedPass);
|
KeyStoreHelper.saveWalletUserPass(LoginActivity.this, newName, savedPass);
|
||||||
KeyStoreHelper.removeWalletUserPass(LoginActivity.this, params[0]);
|
|
||||||
}
|
}
|
||||||
} catch (KeyStoreException ex) {
|
} catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
|
||||||
ex.printStackTrace();
|
Timber.w(ex);
|
||||||
|
} finally {
|
||||||
|
// we have either set a new password or it is broken - kill the old one either way
|
||||||
|
KeyStoreHelper.removeWalletUserPass(LoginActivity.this, oldName);
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@@ -1006,11 +1007,11 @@ public class LoginActivity extends SecureActivity
|
|||||||
case R.id.action_privacy_policy:
|
case R.id.action_privacy_policy:
|
||||||
PrivacyFragment.display(getSupportFragmentManager());
|
PrivacyFragment.display(getSupportFragmentManager());
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_testnet:
|
case R.id.action_stagenet:
|
||||||
try {
|
try {
|
||||||
LoginFragment loginFragment = (LoginFragment)
|
LoginFragment loginFragment = (LoginFragment)
|
||||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||||
item.setChecked(loginFragment.onTestnetMenuItem());
|
item.setChecked(loginFragment.onStagenetMenuItem());
|
||||||
} catch (ClassCastException ex) {
|
} catch (ClassCastException ex) {
|
||||||
// never mind then
|
// never mind then
|
||||||
}
|
}
|
||||||
|
@@ -18,15 +18,12 @@ package com.m2049r.xmrwallet;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -41,14 +38,11 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
|
||||||
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
|
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.model.NetworkType;
|
import com.m2049r.xmrwallet.model.NetworkType;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
@@ -343,69 +337,65 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.list_menu, menu);
|
inflater.inflate(R.menu.list_menu, menu);
|
||||||
menu.findItem(R.id.action_testnet).setChecked(testnetCheckMenu);
|
menu.findItem(R.id.action_stagenet).setChecked(stagenetCheckMenu);
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean testnetCheckMenu = BuildConfig.DEBUG;
|
private boolean stagenetCheckMenu = BuildConfig.DEBUG;
|
||||||
|
|
||||||
//boolean isTestnet() {
|
public boolean onStagenetMenuItem() {
|
||||||
// return testnet;
|
boolean lastState = stagenetCheckMenu;
|
||||||
//}
|
|
||||||
|
|
||||||
public boolean onTestnetMenuItem() {
|
|
||||||
boolean lastState = testnetCheckMenu;
|
|
||||||
setNet(!lastState, true); // set and save
|
setNet(!lastState, true); // set and save
|
||||||
return !lastState;
|
return !lastState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNet(boolean testnetChecked, boolean save) {
|
public void setNet(boolean stagenetChecked, boolean save) {
|
||||||
this.testnetCheckMenu = testnetChecked;
|
this.stagenetCheckMenu = stagenetChecked;
|
||||||
NetworkType net = testnetChecked ? NetworkType.NetworkType_Testnet : NetworkType.NetworkType_Mainnet;
|
NetworkType net = stagenetChecked ? NetworkType.NetworkType_Stagenet : NetworkType.NetworkType_Mainnet;
|
||||||
activityCallback.setNetworkType(net);
|
activityCallback.setNetworkType(net);
|
||||||
activityCallback.showNet();
|
activityCallback.showNet();
|
||||||
if (save) {
|
if (save) {
|
||||||
savePrefs(true); // use previous state as we just clicked it
|
savePrefs(true); // use previous state as we just clicked it
|
||||||
}
|
}
|
||||||
if (testnetChecked) {
|
if (stagenetChecked) {
|
||||||
setDaemon(daemonTestNet);
|
setDaemon(daemonStageNet);
|
||||||
} else {
|
} else {
|
||||||
setDaemon(daemonMainNet);
|
setDaemon(daemonMainNet);
|
||||||
}
|
}
|
||||||
loadList();
|
loadList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String PREF_DAEMON_TESTNET = "daemon_testnet";
|
private static final String PREF_DAEMON_STAGENET = "daemon_stagenet";
|
||||||
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
|
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
|
||||||
|
|
||||||
private static final String PREF_DAEMONLIST_MAINNET =
|
private static final String PREF_DAEMONLIST_MAINNET =
|
||||||
"node.moneroworld.com:18089;node.xmrbackb.one;node.xmr.be";
|
"node.moneroworld.com:18089;node.xmrbackb.one;node.xmr.be";
|
||||||
|
|
||||||
private static final String PREF_DAEMONLIST_TESTNET =
|
private static final String PREF_DAEMONLIST_STAGENET =
|
||||||
"testnet.xmrchain.net";
|
"stagenet.xmr-tw.org";
|
||||||
|
|
||||||
private NodeList daemonTestNet;
|
private NodeList daemonStageNet;
|
||||||
private NodeList daemonMainNet;
|
private NodeList daemonMainNet;
|
||||||
|
|
||||||
void loadPrefs() {
|
void loadPrefs() {
|
||||||
SharedPreferences sharedPref = activityCallback.getPrefs();
|
SharedPreferences sharedPref = activityCallback.getPrefs();
|
||||||
|
|
||||||
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
|
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
|
||||||
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, PREF_DAEMONLIST_TESTNET));
|
daemonStageNet = new NodeList(sharedPref.getString(PREF_DAEMON_STAGENET, PREF_DAEMONLIST_STAGENET));
|
||||||
setNet(testnetCheckMenu, false);
|
setNet(stagenetCheckMenu, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void savePrefs() {
|
void savePrefs() {
|
||||||
savePrefs(false);
|
savePrefs(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void savePrefs(boolean usePreviousTestnetState) {
|
void savePrefs(boolean usePreviousNetState) {
|
||||||
Timber.d("SAVE / %s", usePreviousTestnetState);
|
Timber.d("SAVE / %s", usePreviousNetState);
|
||||||
// save the daemon address for the net
|
// save the daemon address for the net
|
||||||
boolean testnet = testnetCheckMenu ^ usePreviousTestnetState;
|
boolean stagenet = stagenetCheckMenu ^ usePreviousNetState;
|
||||||
String daemon = getDaemon();
|
String daemon = getDaemon();
|
||||||
if (testnet) {
|
if (stagenet) {
|
||||||
daemonTestNet.setRecent(daemon);
|
daemonStageNet.setRecent(daemon);
|
||||||
} else {
|
} else {
|
||||||
daemonMainNet.setRecent(daemon);
|
daemonMainNet.setRecent(daemon);
|
||||||
}
|
}
|
||||||
@@ -413,7 +403,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
SharedPreferences sharedPref = activityCallback.getPrefs();
|
SharedPreferences sharedPref = activityCallback.getPrefs();
|
||||||
SharedPreferences.Editor editor = sharedPref.edit();
|
SharedPreferences.Editor editor = sharedPref.edit();
|
||||||
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString());
|
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet.toString());
|
||||||
editor.putString(PREF_DAEMON_TESTNET, daemonTestNet.toString());
|
editor.putString(PREF_DAEMON_STAGENET, daemonStageNet.toString());
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -133,6 +133,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||||||
acquireWakeLock();
|
acquireWakeLock();
|
||||||
String walletId = extras.getString(REQUEST_ID);
|
String walletId = extras.getString(REQUEST_ID);
|
||||||
needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED);
|
needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED);
|
||||||
|
password = extras.getString(REQUEST_PW);
|
||||||
connectWalletService(walletId, password);
|
connectWalletService(walletId, password);
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
@@ -259,8 +260,6 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
|
|||||||
.add(R.id.fragment_container, walletFragment, WalletFragment.class.getName()).commit();
|
.add(R.id.fragment_container, walletFragment, WalletFragment.class.getName()).commit();
|
||||||
Timber.d("fragment added");
|
Timber.d("fragment added");
|
||||||
|
|
||||||
password = getIntent().getExtras().getString(REQUEST_PW);
|
|
||||||
|
|
||||||
startWalletService();
|
startWalletService();
|
||||||
Timber.d("onCreate() done.");
|
Timber.d("onCreate() done.");
|
||||||
}
|
}
|
||||||
|
@@ -233,7 +233,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private boolean isBitcoinAddress() {
|
private boolean isBitcoinAddress() {
|
||||||
String address = etAddress.getEditText().getText().toString();
|
String address = etAddress.getEditText().getText().toString();
|
||||||
if ((address.length() >= 27) && (address.length() <= 34))
|
if ((address.length() >= 27) && (address.length() <= 35))
|
||||||
return BitcoinAddressValidator.validate(address);
|
return BitcoinAddressValidator.validate(address);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@@ -247,7 +247,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private XmrToApi xmrToApi = null;
|
private XmrToApi xmrToApi = null;
|
||||||
|
|
||||||
private final XmrToApi getXmrToApi() {
|
private XmrToApi getXmrToApi() {
|
||||||
if (xmrToApi == null) {
|
if (xmrToApi == null) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (xmrToApi == null) {
|
if (xmrToApi == null) {
|
||||||
|
@@ -164,8 +164,6 @@ public class Wallet {
|
|||||||
|
|
||||||
public static native boolean isAddressValid(String address, int networkType);
|
public static native boolean isAddressValid(String address, int networkType);
|
||||||
|
|
||||||
//TODO static static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error);
|
|
||||||
|
|
||||||
public static native String getPaymentIdFromAddress(String address, int networkType);
|
public static native String getPaymentIdFromAddress(String address, int networkType);
|
||||||
|
|
||||||
public static native long getMaximumAllowedAmount();
|
public static native long getMaximumAllowedAmount();
|
||||||
|
@@ -228,7 +228,6 @@ public class WalletManager {
|
|||||||
|
|
||||||
public String getDaemonAddress() {
|
public String getDaemonAddress() {
|
||||||
if (daemonAddress == null) {
|
if (daemonAddress == null) {
|
||||||
// assume testnet not explicitly initialised
|
|
||||||
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
|
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
|
||||||
}
|
}
|
||||||
return this.daemonAddress;
|
return this.daemonAddress;
|
||||||
@@ -236,13 +235,13 @@ public class WalletManager {
|
|||||||
|
|
||||||
private native void setDaemonAddressJ(String address);
|
private native void setDaemonAddressJ(String address);
|
||||||
|
|
||||||
String daemonUsername = "";
|
private String daemonUsername = "";
|
||||||
|
|
||||||
public String getDaemonUsername() {
|
public String getDaemonUsername() {
|
||||||
return daemonUsername;
|
return daemonUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
String daemonPassword = "";
|
private String daemonPassword = "";
|
||||||
|
|
||||||
public String getDaemonPassword() {
|
public String getDaemonPassword() {
|
||||||
return daemonPassword;
|
return daemonPassword;
|
||||||
|
@@ -5,8 +5,7 @@ import android.content.Context;
|
|||||||
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
|
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
|
||||||
import android.support.v4.os.CancellationSignal;
|
import android.support.v4.os.CancellationSignal;
|
||||||
|
|
||||||
import java.security.KeyStore;
|
import timber.log.Timber;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
|
|
||||||
public class FingerprintHelper {
|
public class FingerprintHelper {
|
||||||
|
|
||||||
@@ -20,15 +19,13 @@ public class FingerprintHelper {
|
|||||||
fingerprintManager.hasEnrolledFingerprints();
|
fingerprintManager.hasEnrolledFingerprints();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFingerprintAuthAllowed(String wallet) throws KeyStoreException {
|
public static boolean isFingerPassValid(Context context, String wallet) {
|
||||||
KeyStore keyStore = KeyStore.getInstance(KeyStoreHelper.SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
|
|
||||||
try {
|
try {
|
||||||
keyStore.load(null);
|
KeyStoreHelper.loadWalletUserPass(context, wallet);
|
||||||
} catch (Exception ex) {
|
return true;
|
||||||
throw new IllegalStateException("Could not load KeyStore", ex);
|
} catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyStore.containsAlias(KeyStoreHelper.SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void authenticate(Context context, CancellationSignal cancelSignal,
|
public static void authenticate(Context context, CancellationSignal cancelSignal,
|
||||||
@@ -36,5 +33,4 @@ public class FingerprintHelper {
|
|||||||
FingerprintManagerCompat manager = FingerprintManagerCompat.from(context);
|
FingerprintManagerCompat manager = FingerprintManagerCompat.from(context);
|
||||||
manager.authenticate(null, 0, cancelSignal, callback, null);
|
manager.authenticate(null, 0, cancelSignal, callback, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -64,7 +64,6 @@ import java.math.BigInteger;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
@@ -303,6 +302,16 @@ public class Helper {
|
|||||||
else return "";
|
else return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] hexToBytes(String hex) {
|
||||||
|
final int len = hex.length();
|
||||||
|
final byte[] data = new byte[len / 2];
|
||||||
|
for (int i = 0; i < len; i += 2) {
|
||||||
|
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
|
||||||
|
+ Character.digit(hex.charAt(i + 1), 16));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static public void setMoneroHome(Context context) {
|
static public void setMoneroHome(Context context) {
|
||||||
try {
|
try {
|
||||||
String home = getStorage(context, HOME_DIR).getAbsolutePath();
|
String home = getStorage(context, HOME_DIR).getAbsolutePath();
|
||||||
@@ -352,6 +361,18 @@ public class Helper {
|
|||||||
return crazyPass;
|
return crazyPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// or maybe it is a broken CrAzYpass? (of which we have two variants)
|
||||||
|
String brokenCrazyPass2 = KeyStoreHelper.getBrokenCrazyPass(context, password, 2);
|
||||||
|
if ((brokenCrazyPass2 != null)
|
||||||
|
&& WalletManager.getInstance().verifyWalletPassword(walletPath, brokenCrazyPass2, true)) {
|
||||||
|
return brokenCrazyPass2;
|
||||||
|
}
|
||||||
|
String brokenCrazyPass1 = KeyStoreHelper.getBrokenCrazyPass(context, password, 1);
|
||||||
|
if ((brokenCrazyPass1 != null)
|
||||||
|
&& WalletManager.getInstance().verifyWalletPassword(walletPath, brokenCrazyPass1, true)) {
|
||||||
|
return brokenCrazyPass1;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,12 +389,7 @@ public class Helper {
|
|||||||
final TextInputLayout etPassword = (TextInputLayout) promptsView.findViewById(R.id.etPassword);
|
final TextInputLayout etPassword = (TextInputLayout) promptsView.findViewById(R.id.etPassword);
|
||||||
etPassword.setHint(context.getString(R.string.prompt_password, wallet));
|
etPassword.setHint(context.getString(R.string.prompt_password, wallet));
|
||||||
|
|
||||||
boolean fingerprintAuthCheck;
|
final boolean fingerprintAuthCheck = FingerprintHelper.isFingerPassValid(context, wallet);
|
||||||
try {
|
|
||||||
fingerprintAuthCheck = FingerprintHelper.isFingerprintAuthAllowed(wallet);
|
|
||||||
} catch (KeyStoreException ex) {
|
|
||||||
fingerprintAuthCheck = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean fingerprintAuthAllowed = !fingerprintDisabled && fingerprintAuthCheck;
|
final boolean fingerprintAuthAllowed = !fingerprintDisabled && fingerprintAuthCheck;
|
||||||
final CancellationSignal cancelSignal = new CancellationSignal();
|
final CancellationSignal cancelSignal = new CancellationSignal();
|
||||||
@@ -425,13 +441,18 @@ public class Helper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
|
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
|
||||||
String userPass = KeyStoreHelper.loadWalletUserPass(context, wallet);
|
try {
|
||||||
if (Helper.processPasswordEntry(context, wallet, userPass, true, action)) {
|
String userPass = KeyStoreHelper.loadWalletUserPass(context, wallet);
|
||||||
Helper.hideKeyboardAlways((Activity) context);
|
if (Helper.processPasswordEntry(context, wallet, userPass, true, action)) {
|
||||||
openDialog.dismiss();
|
Helper.hideKeyboardAlways((Activity) context);
|
||||||
openDialog = null;
|
openDialog.dismiss();
|
||||||
} else {
|
openDialog = null;
|
||||||
|
} else {
|
||||||
|
etPassword.setError(context.getString(R.string.bad_password));
|
||||||
|
}
|
||||||
|
} catch (KeyStoreHelper.BrokenPasswordStoreException ex) {
|
||||||
etPassword.setError(context.getString(R.string.bad_password));
|
etPassword.setError(context.getString(R.string.bad_password));
|
||||||
|
// TODO: better errror message here - what would it be?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,6 +476,7 @@ public class Helper {
|
|||||||
String pass = etPassword.getEditText().getText().toString();
|
String pass = etPassword.getEditText().getText().toString();
|
||||||
if (processPasswordEntry(context, wallet, pass, false, action)) {
|
if (processPasswordEntry(context, wallet, pass, false, action)) {
|
||||||
Helper.hideKeyboardAlways((Activity) context);
|
Helper.hideKeyboardAlways((Activity) context);
|
||||||
|
cancelSignal.cancel();
|
||||||
openDialog.dismiss();
|
openDialog.dismiss();
|
||||||
openDialog = null;
|
openDialog = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -472,6 +494,7 @@ public class Helper {
|
|||||||
String pass = etPassword.getEditText().getText().toString();
|
String pass = etPassword.getEditText().getText().toString();
|
||||||
if (processPasswordEntry(context, wallet, pass, false, action)) {
|
if (processPasswordEntry(context, wallet, pass, false, action)) {
|
||||||
Helper.hideKeyboardAlways((Activity) context);
|
Helper.hideKeyboardAlways((Activity) context);
|
||||||
|
cancelSignal.cancel();
|
||||||
openDialog.dismiss();
|
openDialog.dismiss();
|
||||||
openDialog = null;
|
openDialog = null;
|
||||||
} else {
|
} else {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,10 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_testnet"
|
android:id="@+id/action_stagenet"
|
||||||
android:checkable="true"
|
android:checkable="true"
|
||||||
android:orderInCategory="100"
|
android:orderInCategory="100"
|
||||||
android:title="@string/menu_testnet"
|
android:title="@string/menu_stagenet"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="wallet_activity_name">Wallet</string>
|
<string name="wallet_activity_name">Wallet</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
|
||||||
<string name="menu_about">Über</string>
|
<string name="menu_about">Über</string>
|
||||||
<string name="menu_privacy">Datenschutzerklärung</string>
|
<string name="menu_privacy">Datenschutzerklärung</string>
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="wallet_activity_name">Monedero</string>
|
<string name="wallet_activity_name">Monedero</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
|
||||||
<string name="menu_about">Acerca De</string>
|
<string name="menu_about">Acerca De</string>
|
||||||
<string name="menu_privacy">Política de Privacidad</string>
|
<string name="menu_privacy">Política de Privacidad</string>
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="wallet_activity_name">Portefeuille</string>
|
<string name="wallet_activity_name">Portefeuille</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
|
||||||
<string name="menu_about">À Propos</string>
|
<string name="menu_about">À Propos</string>
|
||||||
<string name="menu_privacy">Politique de Confidentialité</string>
|
<string name="menu_privacy">Politique de Confidentialité</string>
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="wallet_activity_name">Portafoglio</string>
|
<string name="wallet_activity_name">Portafoglio</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
|
||||||
<string name="menu_about">Informazioni</string>
|
<string name="menu_about">Informazioni</string>
|
||||||
<string name="menu_privacy">Politiche Privacy</string>
|
<string name="menu_privacy">Politiche Privacy</string>
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="wallet_activity_name">Lommebok</string>
|
<string name="wallet_activity_name">Lommebok</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnett</string>
|
|
||||||
<string name="menu_about">Om</string>
|
<string name="menu_about">Om</string>
|
||||||
<string name="menu_privacy">Personvernserklæring</string>
|
<string name="menu_privacy">Personvernserklæring</string>
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="wallet_activity_name">钱包</string>
|
<string name="wallet_activity_name">钱包</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
|
||||||
<string name="menu_about">关于</string>
|
<string name="menu_about">关于</string>
|
||||||
<string name="menu_privacy">隐私权政策</string>
|
<string name="menu_privacy">隐私权政策</string>
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="wallet_activity_name">錢包</string>
|
<string name="wallet_activity_name">錢包</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
|
||||||
<string name="menu_about">關於</string>
|
<string name="menu_about">關於</string>
|
||||||
<string name="menu_privacy">隱私權政策</string>
|
<string name="menu_privacy">隱私權政策</string>
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<string name="app_name" translatable="false">monerujo</string>
|
<string name="app_name" translatable="false">monerujo</string>
|
||||||
<string name="wallet_activity_name">Wallet</string>
|
<string name="wallet_activity_name">Wallet</string>
|
||||||
|
|
||||||
<string name="menu_testnet">Testnet</string>
|
<string name="menu_stagenet" translatable="false">Stagenet</string>
|
||||||
<string name="menu_about">About</string>
|
<string name="menu_about">About</string>
|
||||||
<string name="menu_privacy">Privacy Policy</string>
|
<string name="menu_privacy">Privacy Policy</string>
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ public class BitcoinAddressValidatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void validateBTC_shouldValidate() {
|
public void validateBTC_shouldValidate() {
|
||||||
|
assertTrue(BitcoinAddressValidator.validate("2NBMEXXS4v8ubajzfQUjYvh2ptLkxzH8uTC", true));
|
||||||
assertTrue(BitcoinAddressValidator.validate("2N9fzq66uZYQXp7uqrPBH6jKBhjrgTzpGCy", true));
|
assertTrue(BitcoinAddressValidator.validate("2N9fzq66uZYQXp7uqrPBH6jKBhjrgTzpGCy", true));
|
||||||
assertTrue(BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false));
|
assertTrue(BitcoinAddressValidator.validate("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false));
|
||||||
assertTrue(BitcoinAddressValidator.validate("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", false));
|
assertTrue(BitcoinAddressValidator.validate("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", false));
|
||||||
|
@@ -556,7 +556,8 @@ struct Wallet
|
|||||||
}
|
}
|
||||||
static uint64_t maximumAllowedAmount();
|
static uint64_t maximumAllowedAmount();
|
||||||
// Easylogger wrapper
|
// Easylogger wrapper
|
||||||
static void init(const char *argv0, const char *default_log_base_name);
|
static void init(const char *argv0, const char *default_log_base_name) { init(argv0, default_log_base_name, "", true); }
|
||||||
|
static void init(const char *argv0, const char *default_log_base_name, const std::string &log_path, bool console);
|
||||||
static void debug(const std::string &category, const std::string &str);
|
static void debug(const std::string &category, const std::string &str);
|
||||||
static void info(const std::string &category, const std::string &str);
|
static void info(const std::string &category, const std::string &str);
|
||||||
static void warning(const std::string &category, const std::string &str);
|
static void warning(const std::string &category, const std::string &str);
|
||||||
|
Reference in New Issue
Block a user