From 7d9306ca1a661da015c59a0a991e028aeec0ee44 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 29 Feb 2016 17:39:39 +0300 Subject: [PATCH] Qt wrapper for libwallet - in-progress --- Wallet.cpp | 175 ++++++++++++++++++++++++++++++-- Wallet.h | 33 ++++-- WalletManager.cpp | 66 +++++++----- WalletManager.h | 24 ++++- wizard/WizardCreateWallet.qml | 9 +- wizard/WizardFinish.qml | 2 +- wizard/WizardPassword.qml | 6 +- wizard/WizardRecoveryWallet.qml | 4 + 8 files changed, 275 insertions(+), 44 deletions(-) diff --git a/Wallet.cpp b/Wallet.cpp index 5507f531..61998ab5 100644 --- a/Wallet.cpp +++ b/Wallet.cpp @@ -1,11 +1,82 @@ #include "Wallet.h" +#include +#include +#include +#include + +namespace { + QString TEST_SEED = "bound class paint gasp task soul forgot past pleasure physical circle " + " appear shore bathroom glove women crap busy beauty bliss idea give needle burden"; + + namespace { + bool createFileWrapper(const QString &filename) + { + QFile file(filename); + // qDebug("%s: about to create file: %s", __FUNCTION__, qPrintable(filename)); + bool result = file.open(QIODevice::WriteOnly); + if (!result ){ + qWarning("%s: error creating file '%s' : '%s'", + __FUNCTION__, + qPrintable(filename), + qPrintable(file.errorString())); + } + return result; + } + } + +} struct WalletImpl { - // TODO + + QString basename() const; + void setBasename(const QString &name); + + QString keysName() const; + QString addressName() const; + +// Bitmonero::Wallet * m_walletImpl; + QString m_basename; + QString m_seed; + QString m_password; + QString m_language; + + static QString keysName(const QString &basename); + static QString addressName(const QString &basename); + }; +QString WalletImpl::basename() const +{ + return m_basename; +} + +void WalletImpl::setBasename(const QString &name) +{ + m_basename = name; +} + +QString WalletImpl::keysName() const +{ + return keysName(m_basename); +} + +QString WalletImpl::addressName() const +{ + return addressName(m_basename); +} + +QString WalletImpl::keysName(const QString &basename) +{ + return basename + ".keys"; +} + +QString WalletImpl::addressName(const QString &basename) +{ + return basename + ".address.txt"; +} + Wallet::Wallet(QObject *parent) : QObject(parent) @@ -13,11 +84,9 @@ Wallet::Wallet(QObject *parent) } - QString Wallet::getSeed() const { - return "bound class paint gasp task soul forgot past pleasure physical circle " - " appear shore bathroom glove women crap busy beauty bliss idea give needle burden"; + return m_pimpl->m_seed; } QString Wallet::getSeedLanguage() const @@ -25,7 +94,101 @@ QString Wallet::getSeedLanguage() const return "English"; } -void Wallet::setSeedLaguage(const QString &lang) +//void Wallet::setSeedLaguage(const QString &lang) +//{ +// // TODO: call libwallet's appropriate method +//} + +bool Wallet::setPassword(const QString &password) { - // TODO; + // set/change password implies: + // recovery wallet with existing path, seed and lang + qDebug("%s: recovering wallet with path=%s, seed=%s, lang=%s and new password=%s", + __FUNCTION__, + qPrintable(this->getBasename()), + qPrintable(this->getSeed()), + qPrintable(this->getSeedLanguage()), + qPrintable(password)); + return true; } + +QString Wallet::getPassword() const +{ + return m_pimpl->m_password; +} + +bool Wallet::rename(const QString &name) +{ + + QString dst = QUrl(name).toLocalFile(); + + if (dst.isEmpty()) + dst = name; + + qDebug("%s: renaming '%s' to '%s'", + __FUNCTION__, + qPrintable(m_pimpl->basename()), + qPrintable(dst)); + + QString walletKeysFile = m_pimpl->keysName(); + QString walletAddressFile = m_pimpl->addressName(); + + QString dstWalletKeysFile = WalletImpl::keysName(dst); + QString dstWalletAddressFile = WalletImpl::addressName(dst); + + QFile walletFile(this->getBasename()); + + if (!walletFile.rename(dst)) { + qWarning("Error renaming file: '%s' to '%s' : (%s)", + qPrintable(m_pimpl->basename()), + qPrintable(dst), + qPrintable(walletFile.errorString())); + return false; + } + QFile::rename(walletKeysFile, dstWalletKeysFile); + QFile::rename(walletAddressFile, dstWalletAddressFile); + + bool result = QFile::exists(dst) && QFile::exists(dstWalletKeysFile) + && QFile::exists(dstWalletAddressFile); + + if (result) { + m_pimpl->m_basename = dst; + } + + return result; +} + +QString Wallet::getBasename() const +{ + return m_pimpl->basename(); +} + +int Wallet::error() const +{ + return 0; +} + +QString Wallet::errorString() const +{ + return m_pimpl->m_seed; +} + +Wallet::Wallet(const QString &path, const QString &password, const QString &language) +{ + m_pimpl = new WalletImpl; + m_pimpl->m_basename = path; + m_pimpl->m_password = password; + m_pimpl->m_language = language; + m_pimpl->m_seed = TEST_SEED; + + // Create dummy files for testing + QFileInfo fi(path); + QDir tempDir; + tempDir.mkpath(fi.absolutePath()); + createFileWrapper(m_pimpl->basename()); + createFileWrapper(m_pimpl->keysName()); + createFileWrapper(m_pimpl->addressName()); +} + + + diff --git a/Wallet.h b/Wallet.h index 14018a66..221d3d43 100644 --- a/Wallet.h +++ b/Wallet.h @@ -4,26 +4,41 @@ #include struct WalletImpl; - class Wallet : public QObject { Q_OBJECT Q_PROPERTY(QString seed READ getSeed) public: explicit Wallet(QObject *parent = 0); - QString getSeed() const; - QString getSeedLanguage() const; - void setSeedLaguage(const QString &lang); -signals: -public slots: + + //! returns mnemonic seed + Q_INVOKABLE QString getSeed() const; + + //! returns seed language + Q_INVOKABLE QString getSeedLanguage() const; + + + //! changes the password using existing parameters (path, seed, seed lang) + Q_INVOKABLE bool setPassword(const QString &password); + //! returns curret wallet password + Q_INVOKABLE QString getPassword() const; + + //! renames/moves wallet files + Q_INVOKABLE bool rename(const QString &name); + + //! returns current wallet name (basename, as wallet consists of several files) + Q_INVOKABLE QString getBasename() const; + + Q_INVOKABLE int error() const; + Q_INVOKABLE QString errorString() const; private: + Wallet(const QString &path, const QString &password, const QString &language); - +private: friend class WalletManager; + //! pimpl wrapper for libwallet; WalletImpl * m_pimpl; - - }; #endif // WALLET_H diff --git a/WalletManager.cpp b/WalletManager.cpp index 992dfa4d..4a2f0c8f 100644 --- a/WalletManager.cpp +++ b/WalletManager.cpp @@ -9,21 +9,7 @@ WalletManager * WalletManager::m_instance = nullptr; -namespace { - bool createFileWrapper(const QString &filename) - { - QFile file(filename); - // qDebug("%s: about to create file: %s", __FUNCTION__, qPrintable(filename)); - bool result = file.open(QIODevice::WriteOnly); - if (!result ){ - qWarning("%s: error creating file '%s' : '%s'", - __FUNCTION__, - qPrintable(filename), - qPrintable(file.errorString())); - } - return result; - } -} + WalletManager *WalletManager::instance() @@ -38,24 +24,40 @@ WalletManager *WalletManager::instance() Wallet *WalletManager::createWallet(const QString &path, const QString &password, const QString &language) { - Wallet * wallet = new Wallet(this); - // Create dummy files for testing QFileInfo fi(path); - QDir tempDir; - tempDir.mkpath(fi.absolutePath()); - createFileWrapper(path); - createFileWrapper(path + ".keys"); - createFileWrapper(path + ".address.txt"); + if (fi.exists()) { + qCritical("%s: already exists", __FUNCTION__); + // TODO: set error and error string + // return nullptr; + } + Wallet * wallet = new Wallet(path, password, language); return wallet; } -Wallet *WalletManager::openWallet(const QString &path, const QString &language) +Wallet *WalletManager::openWallet(const QString &path, const QString &language, const QString &password) { + QFileInfo fi(path); + if (fi.exists()) { + qCritical("%s: not exists", __FUNCTION__); + // TODO: set error and error string + // return nullptr; + } + // TODO: call the libwallet api here; + Wallet * wallet = new Wallet(path, password, language); + + return wallet; +} + +Wallet *WalletManager::recoveryWallet(const QString &path, const QString &memo, const QString &language) +{ + // TODO: call the libwallet api here; + return nullptr; } bool WalletManager::moveWallet(const QString &src, const QString &dst_) { + // TODO: move this to libwallet; QFile walletFile(src); if (!walletFile.exists()) { qWarning("%s: source file [%s] doesn't exits", __FUNCTION__, @@ -81,8 +83,26 @@ bool WalletManager::moveWallet(const QString &src, const QString &dst_) return QFile::exists(dst) && QFile::exists(dstWalletKeysFile) && QFile::exists(dstWalletAddressFile); +} +void WalletManager::closeWallet(Wallet *wallet) +{ + delete wallet; +} +QString WalletManager::walletLanguage(const QString &locale) +{ + return "English"; +} + +int WalletManager::error() const +{ + return 0; +} + +QString WalletManager::errorString() const +{ + return tr("Unknown error"); } WalletManager::WalletManager(QObject *parent) : QObject(parent) diff --git a/WalletManager.h b/WalletManager.h index ffb498d7..231f104c 100644 --- a/WalletManager.h +++ b/WalletManager.h @@ -10,11 +10,32 @@ class WalletManager : public QObject Q_OBJECT public: static WalletManager * instance(); + // wizard: createWallet path; Q_INVOKABLE Wallet * createWallet(const QString &path, const QString &password, const QString &language); - Q_INVOKABLE Wallet * openWallet(const QString &path, const QString &language); + // just for future use + Q_INVOKABLE Wallet * openWallet(const QString &path, const QString &language, + const QString &password); + + // wizard: recoveryWallet path; hint: internally it recorvers wallet and set password = "" + Q_INVOKABLE Wallet * recoveryWallet(const QString &path, const QString &memo, + const QString &language); + + // wizard: both "create" and "recovery" paths. + // TODO: probably move it to "Wallet" interface Q_INVOKABLE bool moveWallet(const QString &src, const QString &dst); + //! utils: close wallet to free memory + Q_INVOKABLE void closeWallet(Wallet * wallet); + + //! returns libwallet language name for given locale + Q_INVOKABLE QString walletLanguage(const QString &locale); + + //! returns last error happened in WalletManager + Q_INVOKABLE int error() const; + + //! returns error description in human language + Q_INVOKABLE QString errorString() const; signals: public slots: @@ -22,7 +43,6 @@ public slots: private: explicit WalletManager(QObject *parent = 0); static WalletManager * m_instance; - }; #endif // WALLETMANAGER_H diff --git a/wizard/WizardCreateWallet.qml b/wizard/WizardCreateWallet.qml index 91b7447e..ce573e86 100644 --- a/wizard/WizardCreateWallet.qml +++ b/wizard/WizardCreateWallet.qml @@ -46,13 +46,19 @@ Item { settingsObject['wallet_path'] = uiItem.walletPath + var new_wallet_filename = settingsObject.wallet_path + "/" + settingsObject.account_name; // moving wallet files to the new destination, if user changed it if (new_wallet_filename !== settingsObject.wallet_filename) { - walletManager.moveWallet(settingsObject.wallet_filename, new_wallet_filename); + // using previously saved wallet; + settingsObject.wallet.rename(new_wallet_filename); + //walletManager.moveWallet(settingsObject.wallet_filename, new_wallet_filename); } + + // saving wallet_filename; + settingsObject['wallet_filename'] = new_wallet_filename; } function createWallet(settingsObject) { @@ -66,6 +72,7 @@ Item { } else { print("wallet already created. we just stepping back"); } + settingsObject.wallet_filename = wallet_filename } diff --git a/wizard/WizardFinish.qml b/wizard/WizardFinish.qml index 62975d8c..311dfd62 100644 --- a/wizard/WizardFinish.qml +++ b/wizard/WizardFinish.qml @@ -40,7 +40,7 @@ Item { function buildSettingsString() { var str = "
" + qsTr("Language: ") + wizard.settings['language'] + "
" + qsTr("Account name: ") + wizard.settings['account_name'] + "
" - + qsTr("Words: ") + wizard.settings['words'] + "
" + + qsTr("Words: ") + wizard.settings['wallet'].seed + "
" + qsTr("Wallet Path: ") + wizard.settings['wallet_path'] + "
" + qsTr("Enable auto donation: ") + wizard.settings['auto_donations_enabled'] + "
" + qsTr("Auto donation amount: ") + wizard.settings['auto_donations_amount'] + "
" diff --git a/wizard/WizardPassword.qml b/wizard/WizardPassword.qml index d3d033aa..1bcc6213 100644 --- a/wizard/WizardPassword.qml +++ b/wizard/WizardPassword.qml @@ -43,6 +43,10 @@ Item { onOpacityChanged: visible = opacity !== 0 + function saveSettings(settingsObject) { + settingsObject.wallet.setPassword(passwordItem.password) + } + function handlePassword() { // allow to forward step only if passwords match wizard.nextButton.enabled = passwordItem.password === retypePasswordItem.password @@ -54,8 +58,6 @@ Item { - - Row { id: dotsRow anchors.top: parent.top diff --git a/wizard/WizardRecoveryWallet.qml b/wizard/WizardRecoveryWallet.qml index 9093c59a..572d776b 100644 --- a/wizard/WizardRecoveryWallet.qml +++ b/wizard/WizardRecoveryWallet.qml @@ -46,6 +46,10 @@ Item { settingsObject['wallet_path'] = uiItem.walletPath } + function recoveryWallet() { + + } + WizardManageWalletUI { id: uiItem accountNameText: qsTr("My account name")