trezor: support new passphrase entry mechanism

- passphrase can be prompted also when wallet is running (thus added to the wallet listener)
- device/host decision is now made on the host
pull/7/head
Dusan Klinec 4 years ago
parent 38612c1285
commit 86d21a34ba
No known key found for this signature in database
GPG Key ID: 6337E118CCBCE103

@ -0,0 +1,104 @@
// Copyright (c) 2014-2020, 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.
import QtQuick 2.9
import "." as MoneroComponents
Item {
id: root
property var onAcceptedCallback
property var onWalletEntryCallback
property var onRejectedCallback
function open(canEnterOnDevice_) {
var canEnterOnDevice = canEnterOnDevice_ !== null ? canEnterOnDevice_ : canEnterOnDevice
root.visible = true;
if (canEnterOnDevice) {
entryChooserDialog.okText = qsTr("Hardware wallet")
entryChooserDialog.cancelText = qsTr("Computer")
entryChooserDialog.open()
} else {
openPassphraseDialog()
}
}
function openPassphraseDialog() {
root.visible = true
passphraseDialog.openPassphraseDialog()
}
function close() {
root.visible = false;
if (entryChooserDialog.visible)
entryChooserDialog.close()
if (passphraseDialog.visible)
passphraseDialog.close()
}
StandardDialog {
id: entryChooserDialog
title: qsTr("Hardware wallet passphrase") + translationManager.emptyString
text: qsTr("Please select where you want to enter passphrase.\nIt is recommended to enter passphrase on the hardware wallet for better security.") + translationManager.emptyString
onAccepted: {
if (onWalletEntryCallback){
onWalletEntryCallback()
}
}
onRejected: {
openPassphraseDialog()
}
onCloseCallback: {
root.close()
}
}
PasswordDialog {
id: passphraseDialog
anchors.fill: parent
passphraseDialogMode: true
onAcceptedPassphrase: {
if (onAcceptedCallback)
onAcceptedCallback(passphraseDialog.password);
}
onRejectedPassphrase: {
if (onRejectedCallback)
onRejectedCallback();
}
onCloseCallback: {
root.close()
}
}
}

@ -293,6 +293,7 @@ ApplicationWindow {
currentWallet.connectionStatusChanged.disconnect(onWalletConnectionStatusChanged)
currentWallet.deviceButtonRequest.disconnect(onDeviceButtonRequest);
currentWallet.deviceButtonPressed.disconnect(onDeviceButtonPressed);
currentWallet.walletPassphraseNeeded.disconnect(onWalletPassphraseNeededWallet);
currentWallet.transactionCommitted.disconnect(onTransactionCommitted);
middlePanel.paymentClicked.disconnect(handlePayment);
middlePanel.sweepUnmixableClicked.disconnect(handleSweepUnmixable);
@ -360,6 +361,7 @@ ApplicationWindow {
currentWallet.connectionStatusChanged.connect(onWalletConnectionStatusChanged)
currentWallet.deviceButtonRequest.connect(onDeviceButtonRequest);
currentWallet.deviceButtonPressed.connect(onDeviceButtonPressed);
currentWallet.walletPassphraseNeeded.connect(onWalletPassphraseNeededWallet);
currentWallet.transactionCommitted.connect(onTransactionCommitted);
middlePanel.paymentClicked.connect(handlePayment);
middlePanel.sweepUnmixableClicked.connect(handleSweepUnmixable);
@ -558,19 +560,32 @@ ApplicationWindow {
}
}
function onWalletPassphraseNeeded(){
function onWalletPassphraseNeededManager(on_device){
onWalletPassphraseNeeded(walletManager, on_device)
}
function onWalletPassphraseNeededWallet(on_device){
onWalletPassphraseNeeded(currentWallet, on_device)
}
function onWalletPassphraseNeeded(handler, on_device){
hideProcessingSplash();
console.log(">>> wallet passphrase needed: ")
passwordDialog.onAcceptedPassphraseCallback = function() {
walletManager.onPassphraseEntered(passwordDialog.password);
devicePassphraseDialog.onAcceptedCallback = function(passphrase) {
handler.onPassphraseEntered(passphrase, false, false);
appWindow.onWalletOpening();
}
passwordDialog.onRejectedPassphraseCallback = function() {
walletManager.onPassphraseEntered("", true);
devicePassphraseDialog.onWalletEntryCallback = function() {
handler.onPassphraseEntered("", true, false);
appWindow.onWalletOpening();
}
passwordDialog.openPassphraseDialog()
devicePassphraseDialog.onRejectedCallback = function() {
handler.onPassphraseEntered("", false, true);
appWindow.onWalletOpening();
}
devicePassphraseDialog.open(on_device)
}
function onWalletUpdate() {
@ -1295,7 +1310,7 @@ ApplicationWindow {
walletManager.deviceButtonRequest.connect(onDeviceButtonRequest);
walletManager.deviceButtonPressed.connect(onDeviceButtonPressed);
walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete);
walletManager.walletPassphraseNeeded.connect(onWalletPassphraseNeeded);
walletManager.walletPassphraseNeeded.connect(onWalletPassphraseNeededManager);
IPC.uriHandler.connect(onUriHandler);
if(typeof daemonManager != "undefined") {
@ -1512,8 +1527,6 @@ ApplicationWindow {
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
property var onAcceptedPassphraseCallback
property var onRejectedPassphraseCallback
onAccepted: {
if (onAcceptedCallback)
onAcceptedCallback();
@ -1537,14 +1550,13 @@ ApplicationWindow {
informationPopup.open();
}
onRejectedNewPassword: {}
onAcceptedPassphrase: {
if (onAcceptedPassphraseCallback)
onAcceptedPassphraseCallback();
}
onRejectedPassphrase: {
if (onRejectedPassphraseCallback)
onRejectedPassphraseCallback();
}
}
DevicePassphraseDialog {
id: devicePassphraseDialog
visible: false
z: parent.z + 1
anchors.fill: parent
}
InputDialog {
@ -1708,7 +1720,7 @@ ApplicationWindow {
anchors.fill: blurredArea
source: blurredArea
radius: 64
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible || devicePassphraseDialog.visible
}

@ -53,6 +53,7 @@ HEADERS += \
src/main/oscursor.h \
src/libwalletqt/WalletManager.h \
src/libwalletqt/Wallet.h \
src/libwalletqt/PassphraseHelper.h \
src/libwalletqt/PendingTransaction.h \
src/libwalletqt/TransactionHistory.h \
src/libwalletqt/TransactionInfo.h \
@ -91,7 +92,9 @@ SOURCES += src/main/main.cpp \
src/main/clipboardAdapter.cpp \
src/main/oscursor.cpp \
src/libwalletqt/WalletManager.cpp \
src/libwalletqt/WalletListenerImpl.cpp \
src/libwalletqt/Wallet.cpp \
src/libwalletqt/PassphraseHelper.cpp \
src/libwalletqt/PendingTransaction.cpp \
src/libwalletqt/TransactionHistory.cpp \
src/libwalletqt/TransactionInfo.cpp \

@ -99,6 +99,7 @@
<file>components/ProcessingSplash.qml</file>
<file>components/ProgressBar.qml</file>
<file>components/StandardDialog.qml</file>
<file>components/DevicePassphraseDialog.qml</file>
<file>pages/Sign.qml</file>
<file>components/DaemonManagerDialog.qml</file>
<file>version.js</file>

@ -15,7 +15,9 @@ file(GLOB SOURCE_FILES
"main/*.h"
"main/*.cpp"
"libwalletqt/WalletManager.cpp"
"libwalletqt/WalletListenerImpl.cpp"
"libwalletqt/Wallet.cpp"
"libwalletqt/PassphraseHelper.cpp"
"libwalletqt/PendingTransaction.cpp"
"libwalletqt/TransactionHistory.cpp"
"libwalletqt/TransactionInfo.cpp"
@ -29,6 +31,7 @@ file(GLOB SOURCE_FILES
"libwalletqt/UnsignedTransaction.cpp"
"libwalletqt/WalletManager.h"
"libwalletqt/Wallet.h"
"libwalletqt/PassphraseHelper.h"
"libwalletqt/PendingTransaction.h"
"libwalletqt/TransactionHistory.h"
"libwalletqt/TransactionInfo.h"

@ -0,0 +1,70 @@
// Copyright (c) 2014-2020, 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.
#include "PassphraseHelper.h"
#include <QMutexLocker>
#include <QDebug>
Monero::optional<std::string> PassphraseHelper::onDevicePassphraseRequest(bool & on_device)
{
qDebug() << __FUNCTION__;
QMutexLocker locker(&m_mutex_pass);
m_passphrase_on_device = true;
m_passphrase_abort = false;
if (m_prompter != nullptr){
m_prompter->onWalletPassphraseNeeded(on_device);
}
m_cond_pass.wait(&m_mutex_pass);
if (m_passphrase_abort)
{
throw std::runtime_error("Passphrase entry abort");
}
on_device = m_passphrase_on_device;
if (!on_device) {
auto tmpPass = m_passphrase.toStdString();
m_passphrase = QString();
return Monero::optional<std::string>(tmpPass);
} else {
return Monero::optional<std::string>();
}
}
void PassphraseHelper::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort)
{
qDebug() << __FUNCTION__;
QMutexLocker locker(&m_mutex_pass);
m_passphrase = passphrase;
m_passphrase_abort = entry_abort;
m_passphrase_on_device = enter_on_device;
m_cond_pass.wakeAll();
}

@ -0,0 +1,74 @@
// Copyright (c) 2014-2020, 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.
#ifndef MONERO_GUI_PASSPHRASEHELPER_H
#define MONERO_GUI_PASSPHRASEHELPER_H
#include <QtGlobal>
#include <wallet/api/wallet2_api.h>
#include <QMutex>
#include <QPointer>
#include <QWaitCondition>
#include <QMutex>
/**
* Implements component responsible for showing entry prompt to the user,
* typically Wallet / Wallet manager.
*/
class PassprasePrompter {
public:
virtual void onWalletPassphraseNeeded(bool onDevice) = 0;
};
/**
* Implements receiver of the passphrase responsible for passing it back to the wallet,
* typically wallet listener.
*/
class PassphraseReceiver {
public:
virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) = 0;
};
class PassphraseHelper {
public:
PassphraseHelper(PassprasePrompter * prompter=nullptr): m_prompter(prompter) {};
PassphraseHelper(const PassphraseHelper & h): PassphraseHelper(h.m_prompter) {};
Monero::optional<std::string> onDevicePassphraseRequest(bool & on_device);
void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort);
private:
PassprasePrompter * m_prompter;
QWaitCondition m_cond_pass;
QMutex m_mutex_pass;
QString m_passphrase;
bool m_passphrase_abort;
bool m_passphrase_on_device;
};
#endif //MONERO_GUI_PASSPHRASEHELPER_H

@ -58,66 +58,6 @@ namespace {
static constexpr char ATTRIBUTE_SUBADDRESS_ACCOUNT[] ="gui.subaddress_account";
}
class WalletListenerImpl : public Monero::WalletListener
{
public:
WalletListenerImpl(Wallet * w)
: m_wallet(w)
{
}
virtual void moneySpent(const std::string &txId, uint64_t amount) override
{
qDebug() << __FUNCTION__;
emit m_wallet->moneySpent(QString::fromStdString(txId), amount);
}
virtual void moneyReceived(const std::string &txId, uint64_t amount) override
{
qDebug() << __FUNCTION__;
emit m_wallet->moneyReceived(QString::fromStdString(txId), amount);
}
virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override
{
qDebug() << __FUNCTION__;
emit m_wallet->unconfirmedMoneyReceived(QString::fromStdString(txId), amount);
}
virtual void newBlock(uint64_t height) override
{
// qDebug() << __FUNCTION__;
emit m_wallet->newBlock(height, m_wallet->daemonBlockChainTargetHeight());
}
virtual void updated() override
{
emit m_wallet->updated();
}
// called when wallet refreshed by background thread or explicitly
virtual void refreshed() override
{
qDebug() << __FUNCTION__;
emit m_wallet->refreshed();
}
virtual void onDeviceButtonRequest(uint64_t code) override
{
emit m_wallet->deviceButtonRequest(code);
}
virtual void onDeviceButtonPressed() override
{
emit m_wallet->deviceButtonPressed();
}
private:
Wallet * m_wallet;
};
Wallet::Wallet(QObject * parent)
: Wallet(nullptr, parent)
{
@ -1021,6 +961,19 @@ void Wallet::keyReuseMitigation2(bool mitigation)
m_walletImpl->keyReuseMitigation2(mitigation);
}
void Wallet::onWalletPassphraseNeeded(bool on_device)
{
emit this->walletPassphraseNeeded(on_device);
}
void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort)
{
if (m_walletListener != nullptr)
{
m_walletListener->onPassphraseEntered(passphrase, enter_on_device, entry_abort);
}
}
Wallet::Wallet(Monero::Wallet *w, QObject *parent)
: QObject(parent)
, m_walletImpl(w)

@ -41,6 +41,8 @@
#include "PendingTransaction.h" // we need to have an access to the PendingTransaction::Priority enum here;
#include "UnsignedTransaction.h"
#include "NetworkType.h"
#include "PassphraseHelper.h"
#include "WalletListenerImpl.h"
namespace Monero {
struct Wallet; // forward declaration
@ -57,7 +59,7 @@ class SubaddressModel;
class SubaddressAccount;
class SubaddressAccountModel;
class Wallet : public QObject
class Wallet : public QObject, public PassprasePrompter
{
Q_OBJECT
Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged)
@ -348,6 +350,10 @@ public:
Q_INVOKABLE void segregationHeight(quint64 height);
Q_INVOKABLE void keyReuseMitigation2(bool mitigation);
// Passphrase entry for hardware wallets
Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
virtual void onWalletPassphraseNeeded(bool on_device) override;
// TODO: setListenter() when it implemented in API
signals:
// emitted on every event happened with wallet
@ -367,6 +373,7 @@ signals:
void walletCreationHeightChanged();
void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed();
void walletPassphraseNeeded(bool onDevice);
void transactionCommitted(bool status, PendingTransaction *t, const QStringList& txid);
void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const;
void deviceShowAddressShowed();
@ -432,7 +439,7 @@ private:
bool m_connectionStatusRunning;
QString m_daemonUsername;
QString m_daemonPassword;
Monero::WalletListener *m_walletListener;
WalletListenerImpl *m_walletListener;
FutureScheduler m_scheduler;
QMutex m_storeMutex;
};

@ -0,0 +1,97 @@
// Copyright (c) 2014-2020, 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.
#include "WalletListenerImpl.h"
#include "Wallet.h"
WalletListenerImpl::WalletListenerImpl(Wallet * w)
: m_wallet(w)
, m_phelper(w)
{
}
void WalletListenerImpl::moneySpent(const std::string &txId, uint64_t amount)
{
qDebug() << __FUNCTION__;
emit m_wallet->moneySpent(QString::fromStdString(txId), amount);
}
void WalletListenerImpl::moneyReceived(const std::string &txId, uint64_t amount)
{
qDebug() << __FUNCTION__;
emit m_wallet->moneyReceived(QString::fromStdString(txId), amount);
}
void WalletListenerImpl::unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
{
qDebug() << __FUNCTION__;
emit m_wallet->unconfirmedMoneyReceived(QString::fromStdString(txId), amount);
}
void WalletListenerImpl::newBlock(uint64_t height)
{
// qDebug() << __FUNCTION__;
emit m_wallet->newBlock(height, m_wallet->daemonBlockChainTargetHeight());
}
void WalletListenerImpl::updated()
{
emit m_wallet->updated();
}
// called when wallet refreshed by background thread or explicitly
void WalletListenerImpl::refreshed()
{
qDebug() << __FUNCTION__;
emit m_wallet->refreshed();
}
void WalletListenerImpl::onDeviceButtonRequest(uint64_t code)
{
qDebug() << __FUNCTION__;
emit m_wallet->deviceButtonRequest(code);
}
void WalletListenerImpl::onDeviceButtonPressed()
{
qDebug() << __FUNCTION__;
emit m_wallet->deviceButtonPressed();
}
void WalletListenerImpl::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort)
{
qDebug() << __FUNCTION__;
m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort);
}
Monero::optional<std::string> WalletListenerImpl::onDevicePassphraseRequest(bool & on_device)
{
qDebug() << __FUNCTION__;
return m_phelper.onDevicePassphraseRequest(on_device);
}

@ -0,0 +1,68 @@
// Copyright (c) 2014-2020, 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.
#ifndef MONERO_GUI_WALLETLISTENERIMPL_H
#define MONERO_GUI_WALLETLISTENERIMPL_H
#include "wallet/api/wallet2_api.h"
#include "PassphraseHelper.h"
class Wallet;
class WalletListenerImpl : public Monero::WalletListener, public PassphraseReceiver
{
public:
WalletListenerImpl(Wallet * w);
virtual void moneySpent(const std::string &txId, uint64_t amount) override;
virtual void moneyReceived(const std::string &txId, uint64_t amount) override;
virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override;
virtual void newBlock(uint64_t height) override;
virtual void updated() override;
// called when wallet refreshed by background thread or explicitly
virtual void refreshed() override;
virtual void onDeviceButtonRequest(uint64_t code) override;
virtual void onDeviceButtonPressed() override;
virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) override;
virtual Monero::optional<std::string> onDevicePassphraseRequest(bool & on_device) override;
private:
Wallet * m_wallet;
PassphraseHelper m_phelper;
};
#endif //MONERO_GUI_WALLETLISTENERIMPL_H

@ -42,11 +42,12 @@
#include <QString>
#include "qt/updater.h"
#include "qt/ScopeGuard.h"
class WalletPassphraseListenerImpl : public Monero::WalletListener
class WalletPassphraseListenerImpl : public Monero::WalletListener, public PassphraseReceiver
{
public:
WalletPassphraseListenerImpl(WalletManager * mgr): m_mgr(mgr), m_wallet(nullptr) {}
WalletPassphraseListenerImpl(WalletManager * mgr): m_mgr(mgr), m_phelper(mgr) {}
virtual void moneySpent(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; };
virtual void moneyReceived(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; };
@ -55,43 +56,33 @@ public:
virtual void updated() override {};
virtual void refreshed() override {};
virtual Monero::optional<std::string> onDevicePassphraseRequest(bool on_device) override
virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) override
{
qDebug() << __FUNCTION__;
if (on_device) return Monero::optional<std::string>();
m_mgr->onWalletPassphraseNeeded(m_wallet);
if (m_mgr->m_passphrase_abort)
{
throw std::runtime_error("Passphrase entry abort");
}
auto tmpPass = m_mgr->m_passphrase.toStdString();
m_mgr->m_passphrase = QString();
return Monero::optional<std::string>(tmpPass);
m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort);
}
virtual void onDeviceButtonRequest(uint64_t code) override
virtual Monero::optional<std::string> onDevicePassphraseRequest(bool & on_device) override
{
emit m_mgr->deviceButtonRequest(code);
qDebug() << __FUNCTION__;
return m_phelper.onDevicePassphraseRequest(on_device);
}
virtual void onDeviceButtonPressed() override
virtual void onDeviceButtonRequest(uint64_t code) override
{
emit m_mgr->deviceButtonPressed();
qDebug() << __FUNCTION__;
emit m_mgr->deviceButtonRequest(code);
}
virtual void onSetWallet(Monero::Wallet * wallet) override
virtual void onDeviceButtonPressed() override
{
qDebug() << __FUNCTION__;
m_wallet = wallet;
emit m_mgr->deviceButtonPressed();
}
private:
WalletManager * m_mgr;
Monero::Wallet * m_wallet;
PassphraseHelper m_phelper;
};
WalletManager * WalletManager::m_instance = nullptr;
@ -123,6 +114,13 @@ Wallet *WalletManager::openWallet(const QString &path, const QString &password,
{
QMutexLocker locker(&m_mutex);
WalletPassphraseListenerImpl tmpListener(this);
m_mutex_passphraseReceiver.lock();
m_passphraseReceiver = &tmpListener;
m_mutex_passphraseReceiver.unlock();
const auto cleanup = sg::make_scope_guard([this]() noexcept {
QMutexLocker passphrase_locker(&m_mutex_passphraseReceiver);
this->m_passphraseReceiver = nullptr;
});
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
@ -186,6 +184,13 @@ Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString
{
QMutexLocker locker(&m_mutex);
WalletPassphraseListenerImpl tmpListener(this);
m_mutex_passphraseReceiver.lock();
m_passphraseReceiver = &tmpListener;
m_mutex_passphraseReceiver.unlock();
const auto cleanup = sg::make_scope_guard([this]() noexcept {
QMutexLocker passphrase_locker(&m_mutex_passphraseReceiver);
this->m_passphraseReceiver = nullptr;
});
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
@ -529,6 +534,7 @@ bool WalletManager::clearWalletCache(const QString &wallet_path) const
WalletManager::WalletManager(QObject *parent)
: QObject(parent)
, m_passphraseReceiver(nullptr)
, m_scheduler(this)
{
m_pimpl = Monero::WalletManagerFactory::getWalletManager();
@ -539,22 +545,16 @@ WalletManager::~WalletManager()
m_scheduler.shutdownWaitForFinished();
}
void WalletManager::onWalletPassphraseNeeded(Monero::Wallet *)
void WalletManager::onWalletPassphraseNeeded(bool on_device)
{
m_mutex_pass.lock();
m_passphrase_abort = false;
emit this->walletPassphraseNeeded();
m_cond_pass.wait(&m_mutex_pass);
m_mutex_pass.unlock();
emit this->walletPassphraseNeeded(on_device);
}
void WalletManager::onPassphraseEntered(const QString &passphrase, bool entry_abort)
void WalletManager::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort)
{
m_mutex_pass.lock();
m_passphrase = passphrase;
m_passphrase_abort = entry_abort;
m_cond_pass.wakeAll();
m_mutex_pass.unlock();
QMutexLocker locker(&m_mutex_passphraseReceiver);
if (m_passphraseReceiver != nullptr)
{
m_passphraseReceiver->onPassphraseEntered(passphrase, enter_on_device, entry_abort);
}
}

@ -38,13 +38,14 @@
#include <QWaitCondition>
#include "qt/FutureScheduler.h"
#include "NetworkType.h"
#include "PassphraseHelper.h"
class Wallet;
namespace Monero {
struct WalletManager;
}
class WalletManager : public QObject
class WalletManager : public QObject, public PassprasePrompter
{
Q_OBJECT
Q_PROPERTY(bool connected READ connected)
@ -185,14 +186,14 @@ public:
// clear/rename wallet cache
Q_INVOKABLE bool clearWalletCache(const QString &fileName) const;
Q_INVOKABLE void onWalletPassphraseNeeded(Monero::Wallet * wallet);
Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool entry_abort=false);
Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
virtual void onWalletPassphraseNeeded(bool on_device) override;
signals:
void walletOpened(Wallet * wallet);
void walletCreated(Wallet * wallet);
void walletPassphraseNeeded();
void walletPassphraseNeeded(bool onDevice);
void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed();
void checkUpdatesComplete(
@ -216,12 +217,8 @@ private:
Monero::WalletManager * m_pimpl;
mutable QMutex m_mutex;
QPointer<Wallet> m_currentWallet;
QWaitCondition m_cond_pass;
QMutex m_mutex_pass;
QString m_passphrase;
bool m_passphrase_abort;
PassphraseReceiver * m_passphraseReceiver;
QMutex m_mutex_passphraseReceiver;
FutureScheduler m_scheduler;
};

@ -0,0 +1,205 @@
// Author: ricab
// Source: https://github.com/ricab/scope_guard
//
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
#ifndef SCOPE_GUARD_HPP_
#define SCOPE_GUARD_HPP_
#include <type_traits>
#include <utility>
#if __cplusplus >= 201703L && defined(SG_REQUIRE_NOEXCEPT_IN_CPP17)
#define SG_REQUIRE_NOEXCEPT
#endif
namespace sg
{
namespace detail
{
/* --- Some custom type traits --- */
// Type trait determining whether a type is callable with no arguments
template<typename T, typename = void>
struct is_noarg_callable_t
: public std::false_type
{}; // in general, false
template<typename T>
struct is_noarg_callable_t<T, decltype(std::declval<T&&>()())>
: public std::true_type
{}; // only true when call expression valid
// Type trait determining whether a no-argument callable returns void
template<typename T>
struct returns_void_t
: public std::is_same<void, decltype(std::declval<T&&>()())>
{};
/* Type trait determining whether a no-arg callable is nothrow invocable if
required. This is where SG_REQUIRE_NOEXCEPT logic is encapsulated. */
template<typename T>
struct is_nothrow_invocable_if_required_t
: public
#ifdef SG_REQUIRE_NOEXCEPT
std::is_nothrow_invocable<T> /* Note: _r variants not enough to
confirm void return: any return can be
discarded so all returns are
compatible with void */
#else
std::true_type
#endif
{};
// logic AND of two or more type traits
template<typename A, typename B, typename... C>
struct and_t : public and_t<A, and_t<B, C...>>
{}; // for more than two arguments
template<typename A, typename B>
struct and_t<A, B> : public std::conditional<A::value, B, A>::type
{}; // for two arguments
// Type trait determining whether a type is a proper scope_guard callback.
template<typename T>
struct is_proper_sg_callback_t
: public and_t<is_noarg_callable_t<T>,
returns_void_t<T>,
is_nothrow_invocable_if_required_t<T>,
std::is_nothrow_destructible<T>>
{};
/* --- The actual scope_guard template --- */
template<typename Callback,
typename = typename std::enable_if<
is_proper_sg_callback_t<Callback>::value>::type>
class scope_guard;
/* --- Now the friend maker --- */
template<typename Callback>
detail::scope_guard<Callback> make_scope_guard(Callback&& callback)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value); /*
we need this in the inner namespace due to MSVC bugs preventing
sg::detail::scope_guard from befriending a sg::make_scope_guard
template instance in the parent namespace (see https://is.gd/xFfFhE). */
/* --- The template specialization that actually defines the class --- */
template<typename Callback>
class scope_guard<Callback> final
{
public:
typedef Callback callback_type;
scope_guard(scope_guard&& other)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value);
~scope_guard() noexcept; // highlight noexcept dtor
void dismiss() noexcept;
public:
scope_guard() = delete;
scope_guard(const scope_guard&) = delete;
scope_guard& operator=(const scope_guard&) = delete;
scope_guard& operator=(scope_guard&&) = delete;
private:
explicit scope_guard(Callback&& callback)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value); /*
meant for friends only */
friend scope_guard<Callback> make_scope_guard<Callback>(Callback&&)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value); /*
only make_scope_guard can create scope_guards from scratch (i.e. non-move)
*/
private:
Callback m_callback;
bool m_active;
};
} // namespace detail
/* --- Now the single public maker function --- */
using detail::make_scope_guard; // see comment on declaration above
} // namespace sg
////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
sg::detail::scope_guard<Callback>::scope_guard(Callback&& callback)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
: m_callback(std::forward<Callback>(callback)) /* use () instead of {} because
of DR 1467 (https://is.gd/WHmWuo), which still impacts older compilers
(e.g. GCC 4.x and clang <=3.6, see https://godbolt.org/g/TE9tPJ and
https://is.gd/Tsmh8G) */
, m_active{true}
{}
////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
sg::detail::scope_guard<Callback>::~scope_guard() noexcept
{
if(m_active)
m_callback();
}
////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
sg::detail::scope_guard<Callback>::scope_guard(scope_guard&& other)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
: m_callback(std::forward<Callback>(other.m_callback)) // idem
, m_active{std::move(other.m_active)}
{
other.m_active = false;
}
////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
inline void sg::detail::scope_guard<Callback>::dismiss() noexcept
{
m_active = false;
}
////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
inline auto sg::detail::make_scope_guard(Callback&& callback)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
-> detail::scope_guard<Callback>
{
return detail::scope_guard<Callback>{std::forward<Callback>(callback)};
}
#endif /* SCOPE_GUARD_HPP_ */

@ -490,19 +490,24 @@ Rectangle {
walletCreatedFromDevice(success);
}
function onWalletPassphraseNeeded(){
function onWalletPassphraseNeeded(on_device){
splash.close()
console.log(">>> wallet passphrase needed: ");
passwordDialog.onAcceptedPassphraseCallback = function() {
walletManager.onPassphraseEntered(passwordDialog.password);
devicePassphraseDialog.onAcceptedCallback = function(passphrase) {
walletManager.onPassphraseEntered(passphrase, false, false);
creatingWalletDeviceSplash();
}
passwordDialog.onRejectedPassphraseCallback = function() {
walletManager.onPassphraseEntered("", true);
devicePassphraseDialog.onWalletEntryCallback = function() {
walletManager.onPassphraseEntered("", true, false);
creatingWalletDeviceSplash();
}
passwordDialog.openPassphraseDialog()
devicePassphraseDialog.onRejectedCallback = function() {
walletManager.onPassphraseEntered("", false, true);
creatingWalletDeviceSplash();
}
devicePassphraseDialog.open(on_device)
}
function onDeviceButtonRequest(code){