Skip to content

Commit

Permalink
added a debugging option in the settings
Browse files Browse the repository at this point in the history
  • Loading branch information
erasmospunk committed Apr 23, 2016
1 parent 8e312d7 commit ccaaa9c
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 1 deletion.
8 changes: 8 additions & 0 deletions wallet/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="com.coinomi.wallet.ui.SettingsActivity" />
</activity>
<activity
android:name="com.coinomi.wallet.ui.DebuggingActivity"
android:label="@string/title_activity_debugging"
android:theme="@style/AppTheme" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.coinomi.wallet.ui.SettingsActivity" />
</activity>

<provider
android:name="com.coinomi.wallet.ExchangeRatesProvider"
Expand Down
37 changes: 37 additions & 0 deletions wallet/src/main/java/com/coinomi/wallet/ui/DebuggingActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.coinomi.wallet.ui;

import android.os.Bundle;
import android.support.v4.app.Fragment;

import com.coinomi.wallet.R;

/**
* @author John L. Jegutanis
*/
public class DebuggingActivity extends BaseWalletActivity implements UnlockWalletDialog.Listener {

private static final String DEBUGGING_TAG = "debugging_tag";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_wrapper);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new DebuggingFragment(), DEBUGGING_TAG)
.commit();
}

getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(false);
}

@Override
public void onPassword(CharSequence password) {
Fragment f = getFM().findFragmentByTag(DEBUGGING_TAG);
if (f != null && f instanceof DebuggingFragment) {
((DebuggingFragment) f).setPassword(password);
}
}
}
203 changes: 203 additions & 0 deletions wallet/src/main/java/com/coinomi/wallet/ui/DebuggingFragment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package com.coinomi.wallet.ui;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.coinomi.core.wallet.Wallet;
import com.coinomi.wallet.R;
import com.coinomi.wallet.WalletApplication;

import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.crypto.KeyCrypterException;
import org.spongycastle.util.encoders.Hex;

import java.io.UnsupportedEncodingException;
import java.text.Normalizer;
import java.util.Arrays;

import butterknife.ButterKnife;
import butterknife.OnClick;

import static com.coinomi.core.Preconditions.checkNotNull;

/**
* @author John L. Jegutanis
*/
public class DebuggingFragment extends Fragment {
private static final String PROCESSING_DIALOG_TAG = "processing_dialog_tag";
private static final String PASSWORD_DIALOG_TAG = "password_dialog_tag";

private CharSequence password;
private PasswordTestTask passwordTestTask;
private Wallet wallet;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); // for the async task
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_debugging, container, false);
ButterKnife.bind(this, view);

return view;
}

@Override
public void onDestroyView() {
ButterKnife.unbind(this);
super.onDestroyView();
}

@Override
public void onAttach(final Context context) {
super.onAttach(context);
WalletApplication application = (WalletApplication) context.getApplicationContext();
wallet = application.getWallet();
}

@OnClick(R.id.button_execute_password_test)
void onExecutePasswordTest() {
if (wallet.isEncrypted()) {
showUnlockDialog();
} else {
DialogBuilder.warn(getActivity(), R.string.wallet_is_not_locked_message)
.setPositiveButton(R.string.button_ok, null)
.create().show();
}
}

private void showUnlockDialog() {
Dialogs.dismissAllowingStateLoss(getFragmentManager(), PASSWORD_DIALOG_TAG);
UnlockWalletDialog.getInstance().show(getFragmentManager(), PASSWORD_DIALOG_TAG);
}


public void setPassword(CharSequence password) {
this.password = password;
maybeStartPasswordTestTask();
}

private void maybeStartPasswordTestTask() {
if (passwordTestTask == null) {
passwordTestTask = new PasswordTestTask();
passwordTestTask.execute();
}
}

private class PasswordTestTask extends AsyncTask<Void, Void, Void> {
UnlockResult result = new UnlockResult();
Exception error;

@Override
protected void onPreExecute() {
Dialogs.ProgressDialogFragment.show(getFragmentManager(),
getString(R.string.seed_working), PROCESSING_DIALOG_TAG);
}

@Override
protected Void doInBackground(Void... params) {
DeterministicKey masterKey = wallet.getMasterKey();
try {
if (masterKey.getKeyCrypter() != null) {

if (tryDecrypt(masterKey, password)) {
result.isUnlockSuccess = true;
} else {
tryNormalizationDecryption(masterKey, password, result);
}

if (!result.isUnlockSuccess) {
String trimmedPassword = password.toString().trim();
if (!password.equals(trimmedPassword)) {
if (tryDecrypt(masterKey, trimmedPassword)) {
result.isUnlockSuccess = true;
result.isWhitespaceTrimmed = true;
} else {
tryNormalizationDecryption(masterKey, password, result);
result.isWhitespaceTrimmed = true;
}
}
}
} else {
throw new RuntimeException("Missing key crypter");
}
} catch (Exception e) {
error = e;
}

return null;
}

private boolean tryNormalizationDecryption(DeterministicKey masterKey, CharSequence password, UnlockResult result) {
if (tryDecrypt(masterKey, Normalizer.normalize(password, Normalizer.Form.NFC))) {
result.isUnlockSuccess = true;
result.normalization = Normalizer.Form.NFC;
} else if (tryDecrypt(masterKey, Normalizer.normalize(password, Normalizer.Form.NFD))) {
result.isUnlockSuccess = true;
result.normalization = Normalizer.Form.NFD;
} else if (tryDecrypt(masterKey, Normalizer.normalize(password, Normalizer.Form.NFKD))) {
result.isUnlockSuccess = true;
result.normalization = Normalizer.Form.NFKD;
} else if (tryDecrypt(masterKey, Normalizer.normalize(password, Normalizer.Form.NFKC))) {
result.isUnlockSuccess = true;
result.normalization = Normalizer.Form.NFKC;
}
return result.isUnlockSuccess;
}

private boolean tryDecrypt(DeterministicKey masterKey, CharSequence password) {
KeyCrypter crypter = checkNotNull(masterKey.getKeyCrypter());
try {
masterKey.decrypt(crypter, crypter.deriveKey(password));
return true;
} catch (KeyCrypterException e) {
return false;
}
}

protected void onPostExecute(Void aVoid) {
passwordTestTask = null;
if (Dialogs.dismissAllowingStateLoss(getFragmentManager(), PROCESSING_DIALOG_TAG)) return;

if (error != null) {
DialogBuilder.warn(getActivity(), R.string.error_generic)
.setMessage(error.getMessage())
.setPositiveButton(R.string.button_ok, null).create().show();
} else {
String yes = getString(R.string.yes);
String no = getString(R.string.no);
String fingerprint = "";
try {
fingerprint = Hex.toHexString(Arrays.copyOf(
Sha256Hash.create(password.toString().getBytes("UTF-8")).getBytes(), 4));
} catch (UnsupportedEncodingException e) { /* Should not happen */ }

String message = getString(R.string.debugging_test_wallet_password_results,
result.isUnlockSuccess ? yes : no,
result.normalization != null ? result.normalization : "NONE",
result.isWhitespaceTrimmed ? yes : no, fingerprint);
DialogBuilder.warn(getActivity(), R.string.debugging_test_wallet_password)
.setMessage(message)
.setPositiveButton(R.string.button_ok, null).create().show();
}
}
}

static class UnlockResult {
Normalizer.Form normalization;
boolean isUnlockSuccess = false;
boolean isWhitespaceTrimmed = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void onSignResult(final @Nullable Exception error, final @Nullable Exchan
finish();
} else {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.replace(R.id.container, TradeStatusFragment.newInstance(exchange, true));
transaction.commit();
}
Expand Down
51 changes: 51 additions & 0 deletions wallet/src/main/res/layout/fragment_debugging.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context="com.coinomi.wallet.ui.DebuggingActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusableInTouchMode="true"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">

<TextView
style="@style/NormalText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/standard_margin"
android:layout_marginRight="@dimen/standard_margin"
android:text="@string/debugging_info" />


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:gravity="center_vertical">
<TextView
style="@style/NormalText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/standard_margin"
android:layout_marginRight="@dimen/standard_margin"
android:text="@string/debugging_test_wallet_password" />

<Button
android:id="@+id/button_execute_password_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_execute" />
</LinearLayout>

</LinearLayout>
</ScrollView>
9 changes: 9 additions & 0 deletions wallet/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@
<string name="button_agree">Agree</string>
<string name="button_disagree">Disagree</string>
<string name="button_add_coins">+ Coins</string>
<string name="button_execute">Execute</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="scan_qr_code">Scan QR code</string>
<string name="erase_address">Erase address</string>
<string name="copied_to_clipboard">Copied to clipboard</string>
<string name="wallet_title_request">receive</string>
<string name="wallet_title_balance">balance</string>
<string name="wallet_title_send">send</string>
<string name="wallet_locked_message">Your wallet is locked</string>
<string name="wallet_is_not_locked_message">Your wallet is not locked</string>
<string name="unlock_wallet_title">Unlock your wallet</string>
<string name="unlocking_wallet_working">Unlocking your wallet&#8230;</string>
<string name="unlocking_wallet_error_title">Could not unlock your wallet</string>
Expand Down Expand Up @@ -258,6 +262,11 @@
<string name="seed_password_protected">This recovery phrase is protected with a BIP39 passphrase</string>
<!-- Wallet locked -->
<string name="touch_to_decrypt_wallet">Touch to unlock</string>
<!-- Debugging -->
<string name="title_activity_debugging">Debugging</string>
<string name="debugging_info">You can use a collection of tools to debug various issues with your wallet.</string>
<string name="debugging_test_wallet_password">Wallet unlocking tests</string>
<string name="debugging_test_wallet_password_results">Unlocked wallet: %1$s\nUnicode normalization: %2$s\nWhitespace trimmed: %3$s\nInput fingerprint: %4$s</string>
<!-- Overview -->
<string name="title_activity_overview">Overview</string>
<!-- Exchange -->
Expand Down
5 changes: 5 additions & 0 deletions wallet/src/main/res/xml/preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@
android:title="@string/pref_title_manual_receiving_addresses"
android:summary="@string/pref_summary_manual_receiving_addresses"
android:defaultValue="false"/>

<Preference android:title="@string/title_activity_debugging" >
<intent android:targetPackage="@string/app_package"
android:targetClass="com.coinomi.wallet.ui.DebuggingActivity" />
</Preference>
</PreferenceScreen>

0 comments on commit ccaaa9c

Please sign in to comment.