From 3e90f2e22e8b3a0ffcf83b1996f7bd8ba73d5986 Mon Sep 17 00:00:00 2001 From: m2049r Date: Thu, 27 Sep 2018 07:53:01 +0200 Subject: [PATCH] new Ledger interface --- app/build.gradle | 3 +- app/src/main/cpp/device_io_monerujo.hpp | 88 +++++++++++++++++++ app/src/main/cpp/monerujo.cpp | 43 +++++---- app/src/main/cpp/monerujo_ledger.h | 46 ---------- .../com/m2049r/xmrwallet/LoginActivity.java | 2 + .../com/m2049r/xmrwallet/WalletActivity.java | 15 +++- .../com/m2049r/xmrwallet/ledger/Ledger.java | 8 +- .../xmrwallet/service/WalletService.java | 19 ++-- app/src/main/res/values/strings.xml | 1 + external-libs/collect.sh | 6 +- 10 files changed, 141 insertions(+), 90 deletions(-) create mode 100644 app/src/main/cpp/device_io_monerujo.hpp delete mode 100644 app/src/main/cpp/monerujo_ledger.h diff --git a/app/build.gradle b/app/build.gradle index e21a9251..7311a536 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,7 +37,8 @@ android { abi { enable true reset() - include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' + //include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' + include 'arm64-v8a' universalApk true } } diff --git a/app/src/main/cpp/device_io_monerujo.hpp b/app/src/main/cpp/device_io_monerujo.hpp new file mode 100644 index 00000000..226ede36 --- /dev/null +++ b/app/src/main/cpp/device_io_monerujo.hpp @@ -0,0 +1,88 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#if defined(HAVE_MONERUJO) + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief LedgerFind - find Ledger Device and return it's name + * @param buffer - buffer for name of found device + * @param len - length of buffer + * @return 0 - success + * -1 - no device connected / found + * -2 - JVM not found + */ +int LedgerFind(char *buffer, size_t len); + +/** + * @brief LedgerExchange - exchange data with Ledger Device + * @param command - buffer for data to send + * @param cmd_len - length of send to send + * @param response - buffer for received data + * @param max_resp_len - size of receive buffer + * + * @return length of received data in response or -1 if error + */ +int LedgerExchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len); + +#ifdef __cplusplus +} +#endif + +#include "device_io.hpp" + +#pragma once + +namespace hw { + namespace io { + class device_io_monerujo: device_io { + public: + device_io_monerujo() {}; + ~device_io_monerujo() {}; + + void init() {}; + void release() {}; + + void connect(void *params) {}; + void disconnect() {}; + bool connected() const {return true;}; // monerujo is always connected before it gets here + + // returns number of bytes read or -1 on error + int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) { + return LedgerExchange(command, cmd_len, response, max_resp_len); + } + }; + }; +}; + +#endif //#if defined(HAVE_MONERUJO) diff --git a/app/src/main/cpp/monerujo.cpp b/app/src/main/cpp/monerujo.cpp index 89588152..7fdcbf7c 100644 --- a/app/src/main/cpp/monerujo.cpp +++ b/app/src/main/cpp/monerujo.cpp @@ -1386,24 +1386,22 @@ Java_com_m2049r_xmrwallet_model_WalletManager_setLogLevel(JNIEnv *env, jobject i // Ledger Stuff // -#include "monerujo_ledger.h" +#include "device_io_monerujo.hpp" /** * @brief LedgerExchange - exchange data with Ledger Device - * @param pbSendBuffer - buffer for data to send - * @param cbSendLength - length of send buffer - * @param pbRecvBuffer - buffer for received data - * @param pcbRecvLength - pointer to size of receive buffer - * gets set with length of received data on successful return - * @return SCARD_S_SUCCESS - success - * SCARD_E_NO_READERS_AVAILABLE - no device connected / found - * SCARD_E_INSUFFICIENT_BUFFER - pbRecvBuffer is too small for the response + * @param command - buffer for data to send + * @param cmd_len - length of send to send + * @param response - buffer for received data + * @param max_resp_len - size of receive buffer + * + * @return length of received data in response or -1 if error */ -LONG LedgerExchange( - LPCBYTE pbSendBuffer, - DWORD cbSendLength, - LPBYTE pbRecvBuffer, - LPDWORD pcbRecvLength) { +int LedgerExchange( + unsigned char *command, + unsigned int cmd_len, + unsigned char *response, + unsigned int max_resp_len) { LOGD("LedgerExchange"); JNIEnv *jenv; int envStat = attachJVM(&jenv); @@ -1411,30 +1409,29 @@ LONG LedgerExchange( jmethodID exchangeMethod = jenv->GetStaticMethodID(class_Ledger, "Exchange", "([B)[B"); - jsize sendLen = static_cast(cbSendLength); + jsize sendLen = static_cast(cmd_len); jbyteArray dataSend = jenv->NewByteArray(sendLen); - jenv->SetByteArrayRegion(dataSend, 0, sendLen, (jbyte *) pbSendBuffer); + jenv->SetByteArrayRegion(dataSend, 0, sendLen, (jbyte *) command); jbyteArray dataRecv = (jbyteArray) jenv->CallStaticObjectMethod(class_Ledger, exchangeMethod, dataSend); jenv->DeleteLocalRef(dataSend); if (dataRecv == nullptr) { detachJVM(jenv, envStat); LOGD("LedgerExchange SCARD_E_NO_READERS_AVAILABLE"); - return SCARD_E_NO_READERS_AVAILABLE; + return -1; } jsize len = jenv->GetArrayLength(dataRecv); - LOGD("LedgerExchange SCARD_S_SUCCESS %ld/%d", cbSendLength, len); - if (len <= *pcbRecvLength) { - *pcbRecvLength = static_cast(len); - jenv->GetByteArrayRegion(dataRecv, 0, len, (jbyte *) pbRecvBuffer); + LOGD("LedgerExchange SCARD_S_SUCCESS %ld/%d", cmd_len, len); + if (len <= max_resp_len) { + jenv->GetByteArrayRegion(dataRecv, 0, len, (jbyte *) response); jenv->DeleteLocalRef(dataRecv); detachJVM(jenv, envStat); - return SCARD_S_SUCCESS; + return static_cast(len);; } else { jenv->DeleteLocalRef(dataRecv); detachJVM(jenv, envStat); LOGE("LedgerExchange SCARD_E_INSUFFICIENT_BUFFER"); - return SCARD_E_INSUFFICIENT_BUFFER; + return -1; } } diff --git a/app/src/main/cpp/monerujo_ledger.h b/app/src/main/cpp/monerujo_ledger.h deleted file mode 100644 index 7e523bfd..00000000 --- a/app/src/main/cpp/monerujo_ledger.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2018 m2049r - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef XMRWALLET_LEDGER_H -#define XMRWALLET_LEDGER_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define SCARD_S_SUCCESS ((LONG)0x00000000) /**< No error was encountered. */ -#define SCARD_E_INSUFFICIENT_BUFFER ((LONG)0x80100008) /**< The data buffer to receive returned data is too small for the returned data. */ -#define SCARD_E_NO_READERS_AVAILABLE ((LONG)0x8010002E) /**< Cannot find a smart card reader. */ - -typedef long LONG; -typedef unsigned long DWORD; -typedef DWORD *LPDWORD; -typedef unsigned char BYTE; -typedef BYTE *LPBYTE; -typedef const BYTE *LPCBYTE; - -typedef char CHAR; -typedef CHAR *LPSTR; - -int LedgerFind(char *buffer, size_t len); -LONG LedgerExchange(LPCBYTE pbSendBuffer, DWORD cbSendLength, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength); - -#ifdef __cplusplus -} -#endif - -#endif //XMRWALLET_LEDGER_H diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java index 4ab5ba83..888b827e 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java @@ -1177,6 +1177,8 @@ public class LoginActivity extends BaseActivity case Device_Ledger: if (!hasLedger()) { toast(R.string.open_wallet_ledger_missing); + } else { + startWallet(walletName, password, fingerprintUsed); } break; default: diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java index 1dcab3ba..986c1eb1 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java @@ -529,16 +529,23 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste } @Override - public void onWalletStarted(final boolean success) { + public void onWalletStarted(final Wallet.ConnectionStatus connStatus) { runOnUiThread(new Runnable() { public void run() { dismissProgressDialog(); - if (!success) { - Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show(); + switch (connStatus) { + case ConnectionStatus_Disconnected: + Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show(); + break; + case ConnectionStatus_WrongVersion: + Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_wrongversion), Toast.LENGTH_LONG).show(); + break; + case ConnectionStatus_Connected: + break; } } }); - if (!success) { + if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) { finish(); } else { haveWallet = true; diff --git a/app/src/main/java/com/m2049r/xmrwallet/ledger/Ledger.java b/app/src/main/java/com/m2049r/xmrwallet/ledger/Ledger.java index e761b086..5864a8b8 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/ledger/Ledger.java +++ b/app/src/main/java/com/m2049r/xmrwallet/ledger/Ledger.java @@ -34,11 +34,9 @@ import java.io.IOException; import timber.log.Timber; public class Ledger { - // lookahead parameters as suggest on - // https://monero.stackexchange.com/a/9902/8977 (Step 8) - // by dEBRUYNE - static public final int LOOKAHEAD_ACCOUNTS = 3; - static public final int LOOKAHEAD_SUBADDRESSES = 100; + // 5:20 is same as wallet2.cpp::restore() + static public final int LOOKAHEAD_ACCOUNTS = 5; + static public final int LOOKAHEAD_SUBADDRESSES = 20; static public final String SUBADDRESS_LOOKAHEAD = LOOKAHEAD_ACCOUNTS + ":" + LOOKAHEAD_SUBADDRESSES; public static final int SW_OK = 0x9000; diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java index 9248e8c1..59ca28a0 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java +++ b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java @@ -226,7 +226,7 @@ public class WalletService extends Service { void onSetNotes(boolean success); - void onWalletStarted(boolean success); + void onWalletStarted(Wallet.ConnectionStatus walletStatus); void onWalletOpen(Wallet.Device device); } @@ -293,9 +293,9 @@ public class WalletService extends Service { if (walletId != null) { showProgress(getString(R.string.status_wallet_loading)); showProgress(10); - boolean success = start(walletId, walletPw); - if (observer != null) observer.onWalletStarted(success); - if (!success) { + Wallet.ConnectionStatus connStatus = start(walletId, walletPw); + if (observer != null) observer.onWalletStarted(connStatus); + if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) { errorState = true; stop(); } @@ -490,7 +490,7 @@ public class WalletService extends Service { return true; // true is important so that onUnbind is also called next time } - private boolean start(String walletName, String walletPassword) { + private Wallet.ConnectionStatus start(String walletName, String walletPassword) { Timber.d("start()"); startNotfication(); showProgress(getString(R.string.status_wallet_loading)); @@ -498,9 +498,11 @@ public class WalletService extends Service { if (listener == null) { Timber.d("start() loadWallet"); Wallet aWallet = loadWallet(walletName, walletPassword); - if ((aWallet == null) || (aWallet.getConnectionStatus() != Wallet.ConnectionStatus.ConnectionStatus_Connected)) { + Wallet.ConnectionStatus connStatus = Wallet.ConnectionStatus.ConnectionStatus_Disconnected; + if (aWallet != null) connStatus = aWallet.getConnectionStatus(); + if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) { if (aWallet != null) aWallet.close(); - return false; + return connStatus; } listener = new MyWalletListener(); listener.start(); @@ -511,7 +513,7 @@ public class WalletService extends Service { // if we try to refresh the history here we get occasional segfaults! // doesnt matter since we update as soon as we get a new block anyway Timber.d("start() done"); - return true; + return Wallet.ConnectionStatus.ConnectionStatus_Connected; } public void stop() { @@ -551,6 +553,7 @@ public class WalletService extends Service { if (walletMgr.walletExists(path)) { Timber.d("open wallet %s", path); Wallet.Device device = WalletManager.getInstance().queryWalletDevice(path + ".keys", walletPassword); + Timber.d("device is %s", device.toString()); if (observer != null) observer.onWalletOpen(device); wallet = walletMgr.openWallet(path, walletPassword); showProgress(60); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eac5593f..85ea59a7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -119,6 +119,7 @@ Wallet save failed! Connecting … Node connection failed!\nCheck username/password + Node version incompatible! Node connection timed out!\nTry again or another. Node invalid!\nTry another. Cannot reach node!\nTry again or another. diff --git a/external-libs/collect.sh b/external-libs/collect.sh index 36f11bf5..ceb707ca 100755 --- a/external-libs/collect.sh +++ b/external-libs/collect.sh @@ -7,7 +7,7 @@ set -e orig_path=$PATH packages=(boost openssl monero) -archs=(arm arm64 x86 x86_64) +archs=(arm64 x86_64) for arch in ${archs[@]}; do case ${arch} in @@ -32,11 +32,11 @@ for arch in ${archs[@]}; do OUTPUT_DIR=`pwd`/$package/lib/$xarch mkdir -p $OUTPUT_DIR rm -f $OUTPUT_DIR/*.a - cp -a /opt/android/build/$package/$arch/lib/*.a $OUTPUT_DIR + cp -a /media/m2049r/DATA/android/external-libs/build/$package/$arch/lib/*.a $OUTPUT_DIR if [ $package = "monero" -a -d "/opt/android/build/$package/include" ]; then rm -rf $OUTPUT_DIR/../../include - cp -a /opt/android/build/$package/include $OUTPUT_DIR/../.. + cp -a /media/m2049r/DATA/android/external-libs/build/$package/include $OUTPUT_DIR/../.. fi done