Merge pull request 'Open/create view-only wallets' (#53) from dsc/feather:view-only into master
Reviewed-on: feather/feather#53tobtoht-patch-1
commit
36641d73a6
@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "viewonlydialog.h"
|
||||
#include "ui_viewonlydialog.h"
|
||||
|
||||
ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::ViewOnlyDialog), m_ctx(ctx)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight()));
|
||||
ui->label_primaryAddress->setText(ctx->currentWallet->address(0, 0));
|
||||
ui->label_secretViewKey->setText(ctx->currentWallet->getSecretViewKey());
|
||||
|
||||
connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboad);
|
||||
connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet);
|
||||
|
||||
ui->btn_Save->setEnabled(!m_ctx->currentWallet->viewOnly());
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void ViewOnlyDialog::onWriteViewOnlyWallet(){
|
||||
QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", QDir::homePath(), "Monero wallet (*.keys)");
|
||||
if(fn.isEmpty()) return;
|
||||
if(!fn.endsWith(".keys")) fn += ".keys";
|
||||
|
||||
QString passwd;
|
||||
QInputDialog passwordDialog(this);
|
||||
passwordDialog.setInputMode(QInputDialog::TextInput);
|
||||
passwordDialog.setTextEchoMode(QLineEdit::Password);
|
||||
passwordDialog.setWindowTitle("View-Only wallet password");
|
||||
passwordDialog.setLabelText("Protect this view-only wallet with a password?");
|
||||
passwordDialog.resize(300, 100);
|
||||
if((bool)passwordDialog.exec())
|
||||
passwd = passwordDialog.textValue();
|
||||
|
||||
m_ctx->currentWallet->createViewOnly(fn, passwd);
|
||||
|
||||
QMessageBox::information(this, "Information", "View-only wallet successfully written to disk.");
|
||||
}
|
||||
|
||||
void ViewOnlyDialog::copyToClipboad() {
|
||||
QString text = "";
|
||||
text += QString("Address: %1\n").arg(ui->label_primaryAddress->text());
|
||||
text += QString("Secret view key: %1\n").arg(ui->label_secretViewKey->text());
|
||||
text += QString("Restore height: %1\n").arg(ui->label_restoreHeight->text());
|
||||
Utils::copyToClipboard(text);
|
||||
}
|
||||
|
||||
ViewOnlyDialog::~ViewOnlyDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_VIEWONLYDIALOG_H
|
||||
#define FEATHER_VIEWONLYDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace Ui {
|
||||
class ViewOnlyDialog;
|
||||
}
|
||||
|
||||
class ViewOnlyDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewOnlyDialog(AppContext *ctx, QWidget *parent = nullptr);
|
||||
~ViewOnlyDialog() override;
|
||||
|
||||
private slots:
|
||||
void onWriteViewOnlyWallet();
|
||||
|
||||
private:
|
||||
Ui::ViewOnlyDialog *ui;
|
||||
AppContext *m_ctx = nullptr;
|
||||
void copyToClipboad();
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_KEYSDIALOG_H
|
@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ViewOnlyDialog</class>
|
||||
<widget class="QDialog" name="ViewOnlyDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>659</width>
|
||||
<height>254</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>View-Only</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Restore height</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_restoreHeight">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Primary address</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_primaryAddress">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Secret view key</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_secretViewKey">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_Copy">
|
||||
<property name="text">
|
||||
<string>Copy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_Save">
|
||||
<property name="text">
|
||||
<string>Create view-only wallet</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ViewOnlyDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ViewOnlyDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include "wizard/viewonlywallet.h"
|
||||
#include "wizard/walletwizard.h"
|
||||
#include "ui_viewonlywallet.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QTextCharFormat>
|
||||
#include <QPushButton>
|
||||
#include <QButtonGroup>
|
||||
|
||||
#include <monero_seed/wordlist.hpp> // tevador 14 word
|
||||
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
|
||||
ViewOnlyPage::ViewOnlyPage(AppContext *ctx, QWidget *parent) :
|
||||
QWizardPage(parent),
|
||||
ui(new Ui::ViewOnlyPage),
|
||||
m_ctx(ctx) {
|
||||
ui->setupUi(this);
|
||||
this->setTitle("Import view only wallet");
|
||||
ui->label_errorString->hide();
|
||||
|
||||
QFont f("feather");
|
||||
f.setStyleHint(QFont::Monospace);
|
||||
|
||||
auto *viewOnlyViewKeyDummy = new QLineEdit(this);
|
||||
viewOnlyViewKeyDummy->setVisible(false);
|
||||
auto *viewOnlySpendKeyDummy = new QLineEdit(this);
|
||||
viewOnlySpendKeyDummy->setVisible(false);
|
||||
auto *viewOnlyAddressDummy = new QLineEdit(this);
|
||||
viewOnlyAddressDummy->setVisible(false);
|
||||
auto *restoreHeightDummy = new QLineEdit(this);
|
||||
restoreHeightDummy->setVisible(false);
|
||||
|
||||
this->registerField("viewOnlySpendKey", viewOnlySpendKeyDummy);
|
||||
this->registerField("viewOnlyViewKey", viewOnlyViewKeyDummy);
|
||||
this->registerField("viewOnlyAddress", viewOnlyAddressDummy);
|
||||
this->registerField("viewOnlyHeight", restoreHeightDummy);
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
QGuiApplication::restoreOverrideCursor();
|
||||
#endif
|
||||
|
||||
if(m_ctx->networkType == NetworkType::Type::TESTNET) {
|
||||
ui->restoreHeightWidget->hideSlider();
|
||||
} else {
|
||||
// load restoreHeight lookup db
|
||||
ui->restoreHeightWidget->initRestoreHeights(m_ctx->restoreHeights[m_ctx->networkType]);
|
||||
}
|
||||
|
||||
if(m_ctx->networkType == NetworkType::Type::MAINNET) {
|
||||
ui->lineEdit_address->setPlaceholderText("4...");
|
||||
} else if (m_ctx->networkType == NetworkType::Type::STAGENET) {
|
||||
ui->lineEdit_address->setPlaceholderText("5...");
|
||||
}
|
||||
}
|
||||
|
||||
int ViewOnlyPage::nextId() const {
|
||||
return WalletWizard::Page_CreateWallet;
|
||||
}
|
||||
|
||||
void ViewOnlyPage::cleanupPage() const {}
|
||||
|
||||
bool ViewOnlyPage::validatePage() {
|
||||
auto errStyle = "QLineEdit{border: 1px solid red;}";
|
||||
|
||||
ui->lineEdit_address->setStyleSheet("");
|
||||
ui->lineEdit_viewkey->setStyleSheet("");
|
||||
ui->label_errorString->hide();
|
||||
|
||||
unsigned int restoreHeight = ui->restoreHeightWidget->getHeight();
|
||||
auto spendkey = ui->lineEdit_spendkey->text().trimmed();
|
||||
auto viewkey = ui->lineEdit_viewkey->text().trimmed();
|
||||
auto address = ui->lineEdit_address->text().trimmed();
|
||||
|
||||
if(!m_ctx->walletManager->addressValid(address, m_ctx->networkType)){
|
||||
ui->label_errorString->show();
|
||||
ui->label_errorString->setText("Invalid address.");
|
||||
ui->lineEdit_address->setStyleSheet(errStyle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_ctx->walletManager->keyValid(viewkey, address, true, m_ctx->networkType)) {
|
||||
ui->label_errorString->show();
|
||||
ui->label_errorString->setText("Invalid key.");
|
||||
ui->lineEdit_viewkey->setStyleSheet(errStyle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!spendkey.isEmpty() && !m_ctx->walletManager->keyValid(spendkey, address, false, m_ctx->networkType)) {
|
||||
ui->label_errorString->show();
|
||||
ui->label_errorString->setText("Invalid key.");
|
||||
ui->lineEdit_viewkey->setStyleSheet(errStyle);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->setField("viewOnlyViewKey", viewkey);
|
||||
this->setField("viewOnlySpendKey", spendkey);
|
||||
this->setField("viewOnlyAddress", address);
|
||||
this->setField("viewOnlyHeight", restoreHeight);
|
||||
return true;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_WIZARDVIEWONLY_H
|
||||
#define FEATHER_WIZARDVIEWONLY_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QLabel>
|
||||
#include <QWizardPage>
|
||||
#include <QWidget>
|
||||
#include <QTextEdit>
|
||||
#include <QCompleter>
|
||||
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace Ui {
|
||||
class ViewOnlyPage;
|
||||
}
|
||||
|
||||
class ViewOnlyPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewOnlyPage(AppContext *ctx, QWidget *parent = nullptr);
|
||||
bool validatePage() override;
|
||||
int nextId() const override;
|
||||
void cleanupPage() const;
|
||||
|
||||
private:
|
||||
AppContext *m_ctx;
|
||||
QLabel *topLabel;
|
||||
Ui::ViewOnlyPage *ui;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ViewOnlyPage</class>
|
||||
<widget class="QWizardPage" name="ViewOnlyPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>502</width>
|
||||
<height>506</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>ViewOnlyPage</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Standard address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_address"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Secret view key</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_viewkey"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Secret spend key (optional)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_spendkey"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="restoreFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="RestoreHeightWidget" name="restoreHeightWidget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_restoreHeightInfo">
|
||||
<property name="text">
|
||||
<string>You may specify the "restore height". This is the moment the wallet was created, expressed through a blockheight (number). This speeds up wallet refreshes. If you don't know, leave it empty.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_errorString">
|
||||
<property name="text">
|
||||
<string>errorString</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>RestoreHeightWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/restoreheightwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
Reference in new issue