From 062022f9d115702540b8891a5d3259161a8da44d Mon Sep 17 00:00:00 2001 From: tobtoht Date: Thu, 1 Jul 2021 23:00:47 +0200 Subject: [PATCH] Trezor support --- CMakeLists.txt | 6 ++- Dockerfile | 2 + Makefile | 2 +- src/CMakeLists.txt | 4 ++ src/MainWindow.cpp | 56 ++++++++++++++++++-- src/MainWindow.h | 5 ++ src/WindowManager.cpp | 44 ++++++++++++--- src/WindowManager.h | 2 +- src/appcontext.cpp | 5 ++ src/appcontext.h | 2 + src/assets.qrc | 2 + src/assets/images/trezor_unpaired_white.png | Bin 0 -> 1755 bytes src/assets/images/trezor_white.png | Bin 0 -> 2362 bytes src/dialog/SignVerifyDialog.cpp | 6 +++ src/wizard/PageHardwareDevice.cpp | 5 ++ src/wizard/PageHardwareDevice.ui | 8 +-- src/wizard/PageWalletFile.cpp | 9 +++- src/wizard/WalletWizard.cpp | 12 ++++- src/wizard/WalletWizard.h | 9 +++- 19 files changed, 156 insertions(+), 23 deletions(-) create mode 100644 src/assets/images/trezor_unpaired_white.png create mode 100644 src/assets/images/trezor_white.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e52e002..4a730edb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ option(LOCALMONERO "Include LocalMonero module" ON) option(XMRIG "Include XMRig module" ON) option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF) option(CHECK_UPDATES "Enable checking for application updates" OFF) -option(USE_DEVICE_TREZOR "Trezor support compilation" OFF) +option(USE_DEVICE_TREZOR "Trezor support compilation" ON) option(DONATE_BEG "Prompt donation window every once in a while" ON) option(WITH_SCANNER "Enable webcam QR scanner" OFF) @@ -34,7 +34,7 @@ if(DEBUG) set(CMAKE_VERBOSE_MAKEFILE ON) endif() -set(MONERO_HEAD "36fb05da3394505f8033ceb8806b28909617696f") +set(MONERO_HEAD "9e7caf0efe035da08293232a73b41021911d1b5f") set(BUILD_GUI_DEPS ON) set(ARCH "x86-64") set(BUILD_64 ON) @@ -73,6 +73,8 @@ add_subdirectory(monero) set_property(TARGET wallet_merged PROPERTY FOLDER "monero") get_directory_property(ARCH_WIDTH DIRECTORY "monero" DEFINITION ARCH_WIDTH) get_directory_property(UNBOUND_LIBRARY DIRECTORY "monero" DEFINITION UNBOUND_LIBRARY) +get_directory_property(DEVICE_TREZOR_READY DIRECTORY "monero" DEFINITION DEVICE_TREZOR_READY) +get_directory_property(TREZOR_DEP_LIBS DIRECTORY "monero" DEFINITION TREZOR_DEP_LIBS) include(CMakePackageConfigHelpers) include(VersionMonero) diff --git a/Dockerfile b/Dockerfile index a1623616..d77723a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -266,9 +266,11 @@ RUN git clone -b v4.1.1 --depth 1 https://github.com/fukuchi/libqrencode.git && # monero-seed: Required for Feather # Tevador's 14 word seed library +ADD contrib/monero-seed.patch . RUN git clone https://git.featherwallet.org/feather/monero-seed.git && \ cd monero-seed && \ git reset --hard 4674ef09b6faa6fe602ab5ae0b9ca8e1fd7d5e1b && \ + git apply /monero-seed.patch && \ cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && \ make -Cbuild -j$THREADS && \ make -Cbuild install && \ diff --git a/Makefile b/Makefile index dc0c2a30..c17ab0ef 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ CMAKEFLAGS = \ -DINSTALL_VENDORED_LIBUNBOUND=Off \ -DMANUAL_SUBMODULES=1 \ -DSTATIC=On \ - -DUSE_DEVICE_TREZOR=Off \ + -DUSE_DEVICE_TREZOR=On \ $(CMAKEFLAGS_EXTRA) release-static: CMAKEFLAGS += -DBUILD_TAG="linux-x64" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 56d93145..4c369d86 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -250,6 +250,10 @@ target_link_libraries(feather ${LIBZIP_LIBRARIES} ) +if(DEVICE_TREZOR_READY) + target_link_libraries(feather ${TREZOR_DEP_LIBS}) +endif() + if (WITH_SCANNER) target_link_libraries(feather Qt5::Multimedia diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 50d13c0c..732b140d 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -151,7 +151,7 @@ void MainWindow::initStatusBar() { connect(m_statusBtnTor, &StatusBarButton::clicked, this, &MainWindow::menuTorClicked); this->statusBar()->addPermanentWidget(m_statusBtnTor); - m_statusBtnHwDevice = new StatusBarButton(icons()->icon("ledger.png"), "Ledger", this); + m_statusBtnHwDevice = new StatusBarButton(this->hardwareDevicePairedIcon(), this->getHardwareDevice(), this); connect(m_statusBtnHwDevice, &StatusBarButton::clicked, this, &MainWindow::menuHwDeviceClicked); this->statusBar()->addPermanentWidget(m_statusBtnHwDevice); m_statusBtnHwDevice->hide(); @@ -356,6 +356,8 @@ void MainWindow::initWalletContext() { connect(m_ctx.get(), &AppContext::createTransactionSuccess, this, &MainWindow::onCreateTransactionSuccess); connect(m_ctx.get(), &AppContext::transactionCommitted, this, &MainWindow::onTransactionCommitted); connect(m_ctx.get(), &AppContext::deviceError, this, &MainWindow::onDeviceError); + connect(m_ctx.get(), &AppContext::deviceButtonRequest, this, &MainWindow::onDeviceButtonRequest); + connect(m_ctx.get(), &AppContext::deviceButtonPressed, this, &MainWindow::onDeviceButtonPressed); connect(m_ctx.get(), &AppContext::initiateTransaction, this, &MainWindow::onInitiateTransaction); connect(m_ctx.get(), &AppContext::endTransaction, this, &MainWindow::onEndTransaction); connect(m_ctx.get(), &AppContext::customRestoreHeightSet, this, &MainWindow::onCustomRestoreHeightSet); @@ -801,6 +803,26 @@ void MainWindow::updateWidgetIcons() { m_localMoneroWidget->skinChanged(); #endif ui->conversionWidget->skinChanged(); + + m_statusBtnHwDevice->setIcon(this->hardwareDevicePairedIcon()); +} + +QIcon MainWindow::hardwareDevicePairedIcon() { + QString filename; + if (m_ctx->wallet->isLedger()) + filename = "ledger.png"; + else if (m_ctx->wallet->isTrezor()) + filename = ColorScheme::darkScheme ? "trezor_white.png" : "trezor.png"; + return icons()->icon(filename); +} + +QIcon MainWindow::hardwareDeviceUnpairedIcon() { + QString filename; + if (m_ctx->wallet->isLedger()) + filename = "ledger_unpaired.png"; + else if (m_ctx->wallet->isTrezor()) + filename = ColorScheme::darkScheme ? "trezor_unpaired_white.png" : "trezor_unpaired.png"; + return icons()->icon(filename); } void MainWindow::closeEvent(QCloseEvent *event) { @@ -1065,7 +1087,8 @@ void MainWindow::onDeviceError(const QString &error) { if (m_showDeviceError) { return; } - m_statusBtnHwDevice->setIcon(icons()->icon("ledger_unpaired.png")); + + m_statusBtnHwDevice->setIcon(this->hardwareDeviceUnpairedIcon()); while (true) { m_showDeviceError = true; auto result = QMessageBox::question(this, "Hardware device", "Lost connection to hardware device. Attempt to reconnect?"); @@ -1080,11 +1103,38 @@ void MainWindow::onDeviceError(const QString &error) { return; } } - m_statusBtnHwDevice->setIcon(icons()->icon("ledger.png")); + m_statusBtnHwDevice->setIcon(this->hardwareDevicePairedIcon()); m_ctx->wallet->startRefresh(); m_showDeviceError = false; } +void MainWindow::onDeviceButtonRequest(quint64 code) { + if (m_ctx->wallet->isTrezor()) { + switch (code) { + case 8: // Confirm refresh: Do you really want to start refresh? + { + if (m_constructingTransaction) { // This code is also used when signing a tx... + break; + } + + m_splashDialog->setMessage("Confirm refresh on device to proceed."); + m_splashDialog->setIcon(QPixmap(":/assets/images/confirmed.png")); + m_splashDialog->show(); + m_splashDialog->setEnabled(true); + break; + } + } + } +} + +void MainWindow::onDeviceButtonPressed() { + if (m_constructingTransaction) { + return; + } + + m_splashDialog->hide(); +} + void MainWindow::updateNetStats() { if (m_ctx->wallet == nullptr) { m_statusLabelNetStats->setText(""); diff --git a/src/MainWindow.h b/src/MainWindow.h index 6d33806d..3d8557df 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -171,6 +171,8 @@ private slots: void showRestoreHeightDialog(); void importTransaction(); void onDeviceError(const QString &error); + void onDeviceButtonRequest(quint64 code); + void onDeviceButtonPressed(); void menuHwDeviceClicked(); void onUpdatesAvailable(const QJsonObject &updates); void toggleSearchbar(bool enabled); @@ -205,6 +207,9 @@ private: void updateRecentlyOpened(const QString &filename); void updateWidgetIcons(); + QIcon hardwareDevicePairedIcon(); + QIcon hardwareDeviceUnpairedIcon(); + QScopedPointer ui; WindowManager *m_windowManager; QSharedPointer m_ctx; diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index 82d19baa..52177bcf 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -228,7 +228,7 @@ void WindowManager::tryCreateWallet(FeatherSeed seed, const QString &path, const this->onWalletOpened(wallet); } -void WindowManager::tryCreateWalletFromDevice(const QString &path, const QString &password, int restoreHeight) +void WindowManager::tryCreateWalletFromDevice(const QString &path, const QString &password, const QString &deviceName, int restoreHeight) { if (Utils::fileExists(path)) { auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); @@ -237,7 +237,7 @@ void WindowManager::tryCreateWalletFromDevice(const QString &path, const QString } m_openingWallet = true; - m_walletManager->createWalletFromDeviceAsync(path, password, constants::networkType, "Ledger", restoreHeight); + m_walletManager->createWalletFromDeviceAsync(path, password, constants::networkType, deviceName, restoreHeight); } void WindowManager::tryCreateWalletFromKeys(const QString &path, const QString &password, const QString &address, @@ -294,16 +294,36 @@ void WindowManager::handleWalletError(const QString &message) { } void WindowManager::displayWalletErrorMessage(const QString &message) { - QString errMsg = message; + QString errMsg = QString("Error: %1").arg(message); + + // Ledger if (message.contains("No device found")) { - errMsg += "\n\nThis wallet is backed by a hardware device. Make sure the Monero app is opened on the device.\n" + errMsg += "\n\nThis wallet is backed by a Ledger hardware device. Make sure the Monero app is opened on the device.\n" "You may need to restart Feather before the device can get detected."; } if (message.contains("Unable to open device")) { errMsg += "\n\nThe device might be in use by a different application."; #if defined(Q_OS_LINUX) errMsg += "\n\nNote: On Linux you may need to follow the instructions in the link below before the device can be opened:\n" - "https://support.ledger.com/hc/en-us/articles/115005165269-Fix-connection-issues"; + "https://support.ledger.com/hc/en-us/articles/115005165269-Fix-connection-issues"; +#endif + } + + // TREZOR + if (message.contains("Unable to claim libusb device")) { + errMsg += "\n\nThis wallet is backed by a Trezor hardware device. Feather was unable to access the device. " + "Please make sure it is not opened by another program and try again."; + } + if (message.contains("Cannot get a device address")) { + errMsg += "\n\nRestart the Trezor hardware device and try again."; + } + + if (message.contains("Could not connect to the device Trezor") || message.contains("Device connect failed")) { + errMsg += "\n\nThis wallet is backed by a Trezor hardware device. Make sure the device is connected to your computer and unlocked.\n" + "You may need to restart Feather before the device can be detected."; +#if defined(Q_OS_LINUX) + errMsg += "\n\nNote: On Linux you may need to follow the instructions in the link below before the device can be opened:\n" + "https://wiki.trezor.io/Udev_rules"; #endif } @@ -330,7 +350,19 @@ void WindowManager::displayWalletErrorMessage(const QString &message) { // ######################## DEVICE ######################## void WindowManager::onDeviceButtonRequest(quint64 code) { - m_splashDialog->setMessage("Action required on device: Export the view key to open the wallet."); + QString message; + switch (code) { + case 1: // Trezor + message = "Action required on device: enter your PIN to continue."; + break; + case 8: // Trezor + message = "Action required on device: Export watch-only credentials to open the wallet."; + break; + default: + message = "Action required on device: Export the view key to open the wallet."; + } + + m_splashDialog->setMessage(message); m_splashDialog->setIcon(QPixmap(":/assets/images/key.png")); m_splashDialog->show(); m_splashDialog->setEnabled(true); diff --git a/src/WindowManager.h b/src/WindowManager.h index 4a1acb22..2a87469c 100644 --- a/src/WindowManager.h +++ b/src/WindowManager.h @@ -43,7 +43,7 @@ private slots: private: void tryCreateWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset); - void tryCreateWalletFromDevice(const QString &path, const QString &password, int restoreHeight); + void tryCreateWalletFromDevice(const QString &path, const QString &password, const QString &deviceName, int restoreHeight); void tryCreateWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight); bool autoOpenWallet(); diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 006f8c9f..df663007 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -38,6 +38,7 @@ AppContext::AppContext(Wallet *wallet) connect(this->wallet.get(), &Wallet::transactionCreated, this, &AppContext::onTransactionCreated); connect(this->wallet.get(), &Wallet::deviceError, this, &AppContext::onDeviceError); connect(this->wallet.get(), &Wallet::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest); + connect(this->wallet.get(), &Wallet::deviceButtonPressed, this, &AppContext::onDeviceButtonPressed); connect(this->wallet.get(), &Wallet::connectionStatusChanged, [this]{ this->nodes->autoConnect(); }); @@ -190,6 +191,10 @@ void AppContext::onDeviceButtonRequest(quint64 code) { emit deviceButtonRequest(code); } +void AppContext::onDeviceButtonPressed() { + emit deviceButtonPressed(); +} + void AppContext::onDeviceError(const QString &message) { qCritical() << "Device error: " << message; emit deviceError(message); diff --git a/src/appcontext.h b/src/appcontext.h index 1a7d4dbe..093c01c2 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -59,6 +59,7 @@ public slots: void onAmountPrecisionChanged(int precision); void onMultiBroadcast(PendingTransaction *tx); void onDeviceButtonRequest(quint64 code); + void onDeviceButtonPressed(); void onDeviceError(const QString &message); void onTorSettingsChanged(); // should not be here @@ -92,6 +93,7 @@ signals: void initiateTransaction(); void endTransaction(); void deviceButtonRequest(quint64 code); + void deviceButtonPressed(); void deviceError(const QString &message); private: diff --git a/src/assets.qrc b/src/assets.qrc index 9956d8be..4e813206 100644 --- a/src/assets.qrc +++ b/src/assets.qrc @@ -107,7 +107,9 @@ assets/images/tor_logo_disabled.png assets/images/tor_logo.png assets/images/trezor.png + assets/images/trezor_white.png assets/images/trezor_unpaired.png + assets/images/trezor_unpaired_white.png assets/images/unconfirmed.png assets/images/unlock.png assets/images/unlock.svg diff --git a/src/assets/images/trezor_unpaired_white.png b/src/assets/images/trezor_unpaired_white.png new file mode 100644 index 0000000000000000000000000000000000000000..751f6631a007bd6535c08ad58d9437a83b892510 GIT binary patch literal 1755 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 literal 0 HcmV?d00001 diff --git a/src/dialog/SignVerifyDialog.cpp b/src/dialog/SignVerifyDialog.cpp index 65ff1e46..96244e9d 100644 --- a/src/dialog/SignVerifyDialog.cpp +++ b/src/dialog/SignVerifyDialog.cpp @@ -26,6 +26,12 @@ SignVerifyDialog::SignVerifyDialog(Wallet *wallet, QWidget *parent) ui->address->setText(m_wallet->address(0, 0)); ui->address->setCursorPosition(0); + if (m_wallet->isHwBacked()) { + // We don't have the secret spend key to sign messages + ui->btn_Sign->setEnabled(false); + ui->btn_Sign->setToolTip("Message signing is not supported on this hardware device."); + } + ui->btn_Copy->setVisible(false); } diff --git a/src/wizard/PageHardwareDevice.cpp b/src/wizard/PageHardwareDevice.cpp index 6bdb48fd..83a371c6 100644 --- a/src/wizard/PageHardwareDevice.cpp +++ b/src/wizard/PageHardwareDevice.cpp @@ -13,6 +13,10 @@ PageHardwareDevice::PageHardwareDevice(WizardFields *fields, QWidget *parent) , m_fields(fields) { ui->setupUi(this); + + ui->combo_deviceType->addItem("Ledger Nano S", DeviceType::LEDGER_NANO_S); + ui->combo_deviceType->addItem("Ledger Nano X", DeviceType::LEDGER_NANO_X); + ui->combo_deviceType->addItem("Trezor Model T", DeviceType::TREZOR_MODEL_T); } void PageHardwareDevice::initializePage() { @@ -28,6 +32,7 @@ int PageHardwareDevice::nextId() const { } bool PageHardwareDevice::validatePage() { + m_fields->deviceType = static_cast(ui->combo_deviceType->currentData().toInt()); return true; } diff --git a/src/wizard/PageHardwareDevice.ui b/src/wizard/PageHardwareDevice.ui index 736edea4..9d2cc951 100644 --- a/src/wizard/PageHardwareDevice.ui +++ b/src/wizard/PageHardwareDevice.ui @@ -22,13 +22,7 @@ - - - - Ledger Nano S/X - - - + diff --git a/src/wizard/PageWalletFile.cpp b/src/wizard/PageWalletFile.cpp index 4171ae45..2a9373d6 100644 --- a/src/wizard/PageWalletFile.cpp +++ b/src/wizard/PageWalletFile.cpp @@ -98,7 +98,14 @@ QString PageWalletFile::defaultWalletName() { do { QString walletStr = QString("wallet_%1"); if (m_fields->mode == WizardMode::CreateWalletFromDevice) { - walletStr = QString("ledger_%1"); + switch (m_fields->deviceType) { + case DeviceType::LEDGER_NANO_S: + case DeviceType::LEDGER_NANO_X: + walletStr = QString("ledger_%1"); + break; + case DeviceType::TREZOR_MODEL_T: + walletStr = QString("trezor_%1"); + } } walletName = walletStr.arg(count); count++; diff --git a/src/wizard/WalletWizard.cpp b/src/wizard/WalletWizard.cpp index 5501b6d9..f169937a 100644 --- a/src/wizard/WalletWizard.cpp +++ b/src/wizard/WalletWizard.cpp @@ -93,7 +93,17 @@ void WalletWizard::onCreateWallet() { restoreHeight = m_wizardFields.restoreHeight; } - emit createWalletFromDevice(walletPath, m_wizardFields.password, restoreHeight); + QString deviceName; + switch (m_wizardFields.deviceType) { + case DeviceType::LEDGER_NANO_S: + case DeviceType::LEDGER_NANO_X: + deviceName = "Ledger"; + break; + case DeviceType::TREZOR_MODEL_T: + deviceName = "Trezor"; + } + + emit createWalletFromDevice(walletPath, m_wizardFields.password, deviceName, restoreHeight); return; } diff --git a/src/wizard/WalletWizard.h b/src/wizard/WalletWizard.h index 74893cf6..377ea389 100644 --- a/src/wizard/WalletWizard.h +++ b/src/wizard/WalletWizard.h @@ -21,6 +21,12 @@ enum WizardMode { CreateWalletFromDevice }; +enum DeviceType { + LEDGER_NANO_S = 0, + LEDGER_NANO_X, + TREZOR_MODEL_T +}; + struct WizardFields { QString walletName; QString walletDir; @@ -34,6 +40,7 @@ struct WizardFields { WizardMode mode; int restoreHeight = 0; SeedType seedType; + DeviceType deviceType; }; class WalletWizard : public QWizard @@ -63,7 +70,7 @@ signals: void openWallet(QString path, QString password); void defaultWalletDirChanged(QString walletDir); - void createWalletFromDevice(const QString &path, const QString &password, int restoreHeight); + void createWalletFromDevice(const QString &path, const QString &password, const QString &deviceName, int restoreHeight); void createWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight, bool deterministic = false); void createWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset = "");