mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-30 08:44:16 +00:00
Wallet encryption part 2: ask passphrase when needed, add menu options
This commit is contained in:
parent
3f0816e3d9
commit
b7bcaf940d
@ -90,7 +90,8 @@ HEADERS += src/qt/bitcoingui.h \
|
|||||||
src/qt/sendcoinsentry.h \
|
src/qt/sendcoinsentry.h \
|
||||||
src/qt/qvalidatedlineedit.h \
|
src/qt/qvalidatedlineedit.h \
|
||||||
src/qt/bitcoinunits.h \
|
src/qt/bitcoinunits.h \
|
||||||
src/qt/qvaluecombobox.h
|
src/qt/qvaluecombobox.h \
|
||||||
|
src/qt/askpassphrasedialog.h
|
||||||
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
|
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
|
||||||
src/qt/transactiontablemodel.cpp \
|
src/qt/transactiontablemodel.cpp \
|
||||||
src/qt/addresstablemodel.cpp \
|
src/qt/addresstablemodel.cpp \
|
||||||
@ -134,7 +135,8 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
|
|||||||
src/qt/sendcoinsentry.cpp \
|
src/qt/sendcoinsentry.cpp \
|
||||||
src/qt/qvalidatedlineedit.cpp \
|
src/qt/qvalidatedlineedit.cpp \
|
||||||
src/qt/bitcoinunits.cpp \
|
src/qt/bitcoinunits.cpp \
|
||||||
src/qt/qvaluecombobox.cpp
|
src/qt/qvaluecombobox.cpp \
|
||||||
|
src/qt/askpassphrasedialog.cpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
src/qt/bitcoin.qrc
|
src/qt/bitcoin.qrc
|
||||||
@ -146,7 +148,8 @@ FORMS += \
|
|||||||
src/qt/forms/editaddressdialog.ui \
|
src/qt/forms/editaddressdialog.ui \
|
||||||
src/qt/forms/transactiondescdialog.ui \
|
src/qt/forms/transactiondescdialog.ui \
|
||||||
src/qt/forms/overviewpage.ui \
|
src/qt/forms/overviewpage.ui \
|
||||||
src/qt/forms/sendcoinsentry.ui
|
src/qt/forms/sendcoinsentry.ui \
|
||||||
|
src/qt/forms/askpassphrasedialog.ui
|
||||||
|
|
||||||
CODECFORTR = UTF-8
|
CODECFORTR = UTF-8
|
||||||
# for lrelease/lupdate
|
# for lrelease/lupdate
|
||||||
|
@ -64,5 +64,10 @@ Designer: Crobbo (forum)
|
|||||||
Site: https://bitcointalk.org/index.php?topic=32273.0
|
Site: https://bitcointalk.org/index.php?topic=32273.0
|
||||||
License: Public domain
|
License: Public domain
|
||||||
|
|
||||||
|
Icon: src/qt/res/icons/key.png
|
||||||
|
Designer: VisualPharm (Ivan Boyko)
|
||||||
|
Icon Pack: Must Have
|
||||||
|
Site: http://findicons.com/icon/51009/key?id=51009
|
||||||
|
License: Creative Commons Attribution (by)
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,6 +267,14 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
|||||||
else if(type == Receive)
|
else if(type == Receive)
|
||||||
{
|
{
|
||||||
// Generate a new address to associate with given label
|
// Generate a new address to associate with given label
|
||||||
|
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
|
||||||
|
if(!ctx.isValid())
|
||||||
|
{
|
||||||
|
// Unlock wallet failed or was cancelled
|
||||||
|
editStatus = WALLET_UNLOCK_FAILURE;
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
strAddress = CBitcoinAddress(wallet->GetOrReuseKeyFromPool()).ToString();
|
strAddress = CBitcoinAddress(wallet->GetOrReuseKeyFromPool()).ToString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -26,9 +26,10 @@ public:
|
|||||||
|
|
||||||
// Return status of last edit/insert operation
|
// Return status of last edit/insert operation
|
||||||
enum EditStatus {
|
enum EditStatus {
|
||||||
OK = 0,
|
OK,
|
||||||
INVALID_ADDRESS = 1,
|
INVALID_ADDRESS,
|
||||||
DUPLICATE_ADDRESS = 2
|
DUPLICATE_ADDRESS,
|
||||||
|
WALLET_UNLOCK_FAILURE
|
||||||
};
|
};
|
||||||
|
|
||||||
static const QString Send; /* Send addres */
|
static const QString Send; /* Send addres */
|
||||||
|
186
src/qt/askpassphrasedialog.cpp
Normal file
186
src/qt/askpassphrasedialog.cpp
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
#include "askpassphrasedialog.h"
|
||||||
|
#include "ui_askpassphrasedialog.h"
|
||||||
|
|
||||||
|
#include "guiconstants.h"
|
||||||
|
#include "walletmodel.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::AskPassphraseDialog),
|
||||||
|
mode(mode),
|
||||||
|
model(0)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
|
||||||
|
ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
|
||||||
|
ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
|
||||||
|
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case Encrypt: // Ask passphrase x2
|
||||||
|
ui->passLabel1->hide();
|
||||||
|
ui->passEdit1->hide();
|
||||||
|
ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>."));
|
||||||
|
setWindowTitle(tr("Encrypt wallet"));
|
||||||
|
break;
|
||||||
|
case Unlock: // Ask passphrase
|
||||||
|
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
|
||||||
|
ui->passLabel2->hide();
|
||||||
|
ui->passEdit2->hide();
|
||||||
|
ui->passLabel3->hide();
|
||||||
|
ui->passEdit3->hide();
|
||||||
|
setWindowTitle(tr("Unlock wallet"));
|
||||||
|
break;
|
||||||
|
case Decrypt: // Ask passphrase
|
||||||
|
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
|
||||||
|
ui->passLabel2->hide();
|
||||||
|
ui->passEdit2->hide();
|
||||||
|
ui->passLabel3->hide();
|
||||||
|
ui->passEdit3->hide();
|
||||||
|
setWindowTitle(tr("Decrypt wallet"));
|
||||||
|
break;
|
||||||
|
case ChangePass: // Ask old passphrase + new passphrase x2
|
||||||
|
setWindowTitle(tr("Change passphrase"));
|
||||||
|
ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
resize(minimumSize()); // Get rid of extra space in dialog
|
||||||
|
|
||||||
|
textChanged();
|
||||||
|
connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
|
||||||
|
connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
|
||||||
|
connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
|
||||||
|
}
|
||||||
|
|
||||||
|
AskPassphraseDialog::~AskPassphraseDialog()
|
||||||
|
{
|
||||||
|
// Attempt to overwrite text so that they do not linger around in memory
|
||||||
|
ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
|
||||||
|
ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
|
||||||
|
ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AskPassphraseDialog::setModel(WalletModel *model)
|
||||||
|
{
|
||||||
|
this->model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AskPassphraseDialog::accept()
|
||||||
|
{
|
||||||
|
std::string oldpass, newpass1, newpass2;
|
||||||
|
// TODO: mlock memory / munlock on return so they will not be swapped out, really need "mlockedstring" wrapper class to do this safely
|
||||||
|
oldpass.reserve(MAX_PASSPHRASE_SIZE);
|
||||||
|
newpass1.reserve(MAX_PASSPHRASE_SIZE);
|
||||||
|
newpass2.reserve(MAX_PASSPHRASE_SIZE);
|
||||||
|
oldpass.assign(ui->passEdit1->text().toStdString());
|
||||||
|
newpass1.assign(ui->passEdit2->text().toStdString());
|
||||||
|
newpass2.assign(ui->passEdit3->text().toStdString());
|
||||||
|
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case Encrypt: {
|
||||||
|
if(newpass1.empty() || newpass2.empty())
|
||||||
|
{
|
||||||
|
// Cannot encrypt with empty passphrase
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
|
||||||
|
tr("WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!\nAre you sure you wish to encrypt your wallet?"),
|
||||||
|
QMessageBox::Yes|QMessageBox::Cancel,
|
||||||
|
QMessageBox::Cancel);
|
||||||
|
if(retval == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
if(newpass1 == newpass2)
|
||||||
|
{
|
||||||
|
if(model->setWalletEncrypted(true, newpass1))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Wallet encrypted"),
|
||||||
|
tr("Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Wallet encryption failed"),
|
||||||
|
tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
|
||||||
|
}
|
||||||
|
QDialog::accept(); // Success
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Wallet encryption failed"),
|
||||||
|
tr("The supplied passphrases do not match."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QDialog::reject(); // Cancelled
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Unlock:
|
||||||
|
if(!model->setWalletLocked(false, oldpass))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Wallet unlock failed"),
|
||||||
|
tr("The passphrase entered for the wallet decryption was incorrect."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QDialog::accept(); // Success
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Decrypt:
|
||||||
|
if(!model->setWalletEncrypted(false, oldpass))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Wallet decryption failed"),
|
||||||
|
tr("The passphrase entered for the wallet decryption was incorrect."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QDialog::accept(); // Success
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ChangePass:
|
||||||
|
if(newpass1 == newpass2)
|
||||||
|
{
|
||||||
|
if(model->changePassphrase(oldpass, newpass1))
|
||||||
|
{
|
||||||
|
QMessageBox::information(this, tr("Wallet encrypted"),
|
||||||
|
tr("Wallet passphrase was succesfully changed."));
|
||||||
|
QDialog::accept(); // Success
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Wallet encryption failed"),
|
||||||
|
tr("The passphrase entered for the wallet decryption was incorrect."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Wallet encryption failed"),
|
||||||
|
tr("The supplied passphrases do not match."));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AskPassphraseDialog::textChanged()
|
||||||
|
{
|
||||||
|
// Validate input, set Ok button to enabled when accepable
|
||||||
|
bool acceptable = false;
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case Encrypt: // New passphrase x2
|
||||||
|
acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
|
||||||
|
break;
|
||||||
|
case Unlock: // Old passphrase x1
|
||||||
|
case Decrypt:
|
||||||
|
acceptable = !ui->passEdit1->text().isEmpty();
|
||||||
|
break;
|
||||||
|
case ChangePass: // Old passphrase x1, new passphrase x2
|
||||||
|
acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
|
||||||
|
}
|
40
src/qt/askpassphrasedialog.h
Normal file
40
src/qt/askpassphrasedialog.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef ASKPASSPHRASEDIALOG_H
|
||||||
|
#define ASKPASSPHRASEDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class AskPassphraseDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WalletModel;
|
||||||
|
|
||||||
|
class AskPassphraseDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Mode {
|
||||||
|
Encrypt, // Ask passphrase x2
|
||||||
|
Unlock, // Ask passphrase
|
||||||
|
ChangePass, // Ask old passphrase + new passphrase x2
|
||||||
|
Decrypt // Ask passphrase
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit AskPassphraseDialog(Mode mode, QWidget *parent = 0);
|
||||||
|
~AskPassphraseDialog();
|
||||||
|
|
||||||
|
void accept();
|
||||||
|
|
||||||
|
void setModel(WalletModel *model);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::AskPassphraseDialog *ui;
|
||||||
|
Mode mode;
|
||||||
|
WalletModel *model;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void textChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ASKPASSPHRASEDIALOG_H
|
@ -36,6 +36,7 @@
|
|||||||
<file alias="tx_inout">res/icons/tx_inout.png</file>
|
<file alias="tx_inout">res/icons/tx_inout.png</file>
|
||||||
<file alias="lock_closed">res/icons/lock_closed.png</file>
|
<file alias="lock_closed">res/icons/lock_closed.png</file>
|
||||||
<file alias="lock_open">res/icons/lock_open.png</file>
|
<file alias="lock_open">res/icons/lock_open.png</file>
|
||||||
|
<file alias="key">res/icons/key.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/images">
|
<qresource prefix="/images">
|
||||||
<file alias="about">res/images/about.png</file>
|
<file alias="about">res/images/about.png</file>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "overviewpage.h"
|
#include "overviewpage.h"
|
||||||
#include "bitcoinunits.h"
|
#include "bitcoinunits.h"
|
||||||
#include "guiconstants.h"
|
#include "guiconstants.h"
|
||||||
|
#include "askpassphrasedialog.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
@ -48,6 +49,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
|
|||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
clientModel(0),
|
clientModel(0),
|
||||||
walletModel(0),
|
walletModel(0),
|
||||||
|
encryptWalletAction(0),
|
||||||
|
changePassphraseAction(0),
|
||||||
trayIcon(0)
|
trayIcon(0)
|
||||||
{
|
{
|
||||||
resize(850, 550);
|
resize(850, 550);
|
||||||
@ -66,6 +69,9 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
|
|||||||
file->addAction(quitAction);
|
file->addAction(quitAction);
|
||||||
|
|
||||||
QMenu *settings = menuBar()->addMenu(tr("&Settings"));
|
QMenu *settings = menuBar()->addMenu(tr("&Settings"));
|
||||||
|
settings->addAction(encryptWalletAction);
|
||||||
|
settings->addAction(changePassphraseAction);
|
||||||
|
settings->addSeparator();
|
||||||
settings->addAction(optionsAction);
|
settings->addAction(optionsAction);
|
||||||
|
|
||||||
QMenu *help = menuBar()->addMenu(tr("&Help"));
|
QMenu *help = menuBar()->addMenu(tr("&Help"));
|
||||||
@ -199,11 +205,18 @@ void BitcoinGUI::createActions()
|
|||||||
openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
|
openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
|
||||||
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
|
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
|
||||||
exportAction->setToolTip(tr("Export the current view to a file"));
|
exportAction->setToolTip(tr("Export the current view to a file"));
|
||||||
|
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
|
||||||
|
encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
|
||||||
|
encryptWalletAction->setCheckable(true);
|
||||||
|
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this);
|
||||||
|
changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
|
||||||
|
|
||||||
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||||
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
||||||
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
||||||
connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(show()));
|
connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(show()));
|
||||||
|
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
|
||||||
|
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinGUI::setClientModel(ClientModel *clientModel)
|
void BitcoinGUI::setClientModel(ClientModel *clientModel)
|
||||||
@ -254,6 +267,9 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel)
|
|||||||
// Balloon popup for new transaction
|
// Balloon popup for new transaction
|
||||||
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
|
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||||
this, SLOT(incomingTransaction(QModelIndex,int,int)));
|
this, SLOT(incomingTransaction(QModelIndex,int,int)));
|
||||||
|
|
||||||
|
// Ask for passphrase if needed
|
||||||
|
connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinGUI::createTrayIcon()
|
void BitcoinGUI::createTrayIcon()
|
||||||
@ -544,16 +560,53 @@ void BitcoinGUI::setEncryptionStatus(int status)
|
|||||||
{
|
{
|
||||||
case WalletModel::Unencrypted:
|
case WalletModel::Unencrypted:
|
||||||
labelEncryptionIcon->hide();
|
labelEncryptionIcon->hide();
|
||||||
|
encryptWalletAction->setChecked(false);
|
||||||
|
changePassphraseAction->setEnabled(false);
|
||||||
|
encryptWalletAction->setEnabled(true);
|
||||||
break;
|
break;
|
||||||
case WalletModel::Unlocked:
|
case WalletModel::Unlocked:
|
||||||
labelEncryptionIcon->show();
|
labelEncryptionIcon->show();
|
||||||
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||||
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
|
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
|
||||||
|
encryptWalletAction->setChecked(true);
|
||||||
|
changePassphraseAction->setEnabled(true);
|
||||||
|
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
|
||||||
break;
|
break;
|
||||||
case WalletModel::Locked:
|
case WalletModel::Locked:
|
||||||
labelEncryptionIcon->show();
|
labelEncryptionIcon->show();
|
||||||
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||||
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
|
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
|
||||||
|
encryptWalletAction->setChecked(true);
|
||||||
|
changePassphraseAction->setEnabled(true);
|
||||||
|
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::encryptWallet(bool status)
|
||||||
|
{
|
||||||
|
AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
|
||||||
|
AskPassphraseDialog::Decrypt, this);
|
||||||
|
dlg.setModel(walletModel);
|
||||||
|
dlg.exec();
|
||||||
|
|
||||||
|
setEncryptionStatus(walletModel->getEncryptionStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::changePassphrase()
|
||||||
|
{
|
||||||
|
AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
|
||||||
|
dlg.setModel(walletModel);
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::unlockWallet()
|
||||||
|
{
|
||||||
|
// Unlock wallet if needed
|
||||||
|
if(walletModel->getEncryptionStatus() == WalletModel::Locked)
|
||||||
|
{
|
||||||
|
AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
|
||||||
|
dlg.setModel(walletModel);
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -73,6 +73,8 @@ private:
|
|||||||
QAction *optionsAction;
|
QAction *optionsAction;
|
||||||
QAction *openBitcoinAction;
|
QAction *openBitcoinAction;
|
||||||
QAction *exportAction;
|
QAction *exportAction;
|
||||||
|
QAction *encryptWalletAction;
|
||||||
|
QAction *changePassphraseAction;
|
||||||
|
|
||||||
QSystemTrayIcon *trayIcon;
|
QSystemTrayIcon *trayIcon;
|
||||||
TransactionView *transactionView;
|
TransactionView *transactionView;
|
||||||
@ -108,6 +110,9 @@ private slots:
|
|||||||
void aboutClicked();
|
void aboutClicked();
|
||||||
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||||
void incomingTransaction(const QModelIndex & parent, int start, int end);
|
void incomingTransaction(const QModelIndex & parent, int start, int end);
|
||||||
|
void encryptWallet(bool status);
|
||||||
|
void changePassphrase();
|
||||||
|
void unlockWallet();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -92,6 +92,11 @@ void EditAddressDialog::accept()
|
|||||||
tr("The entered address \"%1\" is not a valid bitcoin address.").arg(ui->addressEdit->text()),
|
tr("The entered address \"%1\" is not a valid bitcoin address.").arg(ui->addressEdit->text()),
|
||||||
QMessageBox::Ok, QMessageBox::Ok);
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
return;
|
return;
|
||||||
|
case AddressTableModel::WALLET_UNLOCK_FAILURE:
|
||||||
|
QMessageBox::critical(this, windowTitle(),
|
||||||
|
tr("Could not unlock wallet."),
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
148
src/qt/forms/askpassphrasedialog.ui
Normal file
148
src/qt/forms/askpassphrasedialog.ui
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AskPassphraseDialog</class>
|
||||||
|
<widget class="QDialog" name="AskPassphraseDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>589</width>
|
||||||
|
<height>228</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>550</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="warningLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="passLabel1">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enter passphrase</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="passEdit1">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="passLabel2">
|
||||||
|
<property name="text">
|
||||||
|
<string>New passphrase</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="passEdit2">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="passLabel3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Repeat new passphrase</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="passEdit3">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</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>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>AskPassphraseDialog</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>AskPassphraseDialog</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>
|
@ -4,6 +4,9 @@
|
|||||||
/* Milliseconds between model updates */
|
/* Milliseconds between model updates */
|
||||||
static const int MODEL_UPDATE_DELAY = 500;
|
static const int MODEL_UPDATE_DELAY = 500;
|
||||||
|
|
||||||
|
/* Maximum passphrase length */
|
||||||
|
static const int MAX_PASSPHRASE_SIZE = 1024;
|
||||||
|
|
||||||
/* Size of icons in status bar */
|
/* Size of icons in status bar */
|
||||||
static const int STATUSBAR_ICONSIZE = 16;
|
static const int STATUSBAR_ICONSIZE = 16;
|
||||||
|
|
||||||
|
BIN
src/qt/res/icons/key.png
Normal file
BIN
src/qt/res/icons/key.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -6,6 +6,7 @@
|
|||||||
#include "optionsmodel.h"
|
#include "optionsmodel.h"
|
||||||
#include "sendcoinsentry.h"
|
#include "sendcoinsentry.h"
|
||||||
#include "guiutil.h"
|
#include "guiutil.h"
|
||||||
|
#include "askpassphrasedialog.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
@ -84,6 +85,13 @@ void SendCoinsDialog::on_sendButton_clicked()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WalletModel::UnlockContext ctx(model->requestUnlock());
|
||||||
|
if(!ctx.isValid())
|
||||||
|
{
|
||||||
|
// Unlock wallet was cancelled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients);
|
WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients);
|
||||||
switch(sendstatus.status)
|
switch(sendstatus.status)
|
||||||
{
|
{
|
||||||
@ -118,7 +126,6 @@ void SendCoinsDialog::on_sendButton_clicked()
|
|||||||
tr("Error: Transaction creation failed "),
|
tr("Error: Transaction creation failed "),
|
||||||
QMessageBox::Ok, QMessageBox::Ok);
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
break;
|
break;
|
||||||
break;
|
|
||||||
case WalletModel::TransactionCommitFailed:
|
case WalletModel::TransactionCommitFailed:
|
||||||
QMessageBox::warning(this, tr("Send Coins"),
|
QMessageBox::warning(this, tr("Send Coins"),
|
||||||
tr("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
|
tr("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
|
||||||
|
@ -199,3 +199,79 @@ WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
|
|||||||
return Unlocked;
|
return Unlocked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WalletModel::setWalletEncrypted(bool encrypted, const std::string &passphrase)
|
||||||
|
{
|
||||||
|
if(encrypted)
|
||||||
|
{
|
||||||
|
// Encrypt
|
||||||
|
return wallet->EncryptWallet(passphrase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Decrypt -- TODO; not supported yet
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WalletModel::setWalletLocked(bool locked, const std::string &passPhrase)
|
||||||
|
{
|
||||||
|
if(locked)
|
||||||
|
{
|
||||||
|
// Lock
|
||||||
|
return wallet->Lock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Unlock
|
||||||
|
return wallet->Unlock(passPhrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WalletModel::changePassphrase(const std::string &oldPass, const std::string &newPass)
|
||||||
|
{
|
||||||
|
bool retval;
|
||||||
|
CRITICAL_BLOCK(wallet->cs_vMasterKey)
|
||||||
|
{
|
||||||
|
wallet->Lock(); // Make sure wallet is locked before attempting pass change
|
||||||
|
retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalletModel::UnlockContext implementation
|
||||||
|
WalletModel::UnlockContext WalletModel::requestUnlock()
|
||||||
|
{
|
||||||
|
bool was_locked = getEncryptionStatus() == Locked;
|
||||||
|
if(was_locked)
|
||||||
|
{
|
||||||
|
// Request UI to unlock wallet
|
||||||
|
emit requireUnlock();
|
||||||
|
}
|
||||||
|
// If wallet is still locked, unlock was failed or cancelled, mark context as invalid
|
||||||
|
bool valid = getEncryptionStatus() != Locked;
|
||||||
|
|
||||||
|
return UnlockContext(this, valid, was_locked);
|
||||||
|
}
|
||||||
|
|
||||||
|
WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
|
||||||
|
wallet(wallet),
|
||||||
|
valid(valid),
|
||||||
|
relock(relock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WalletModel::UnlockContext::~UnlockContext()
|
||||||
|
{
|
||||||
|
if(valid && relock)
|
||||||
|
{
|
||||||
|
wallet->setWalletLocked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
|
||||||
|
{
|
||||||
|
// Transfer context; old object no longer relocks wallet
|
||||||
|
*this = rhs;
|
||||||
|
rhs.relock = false;
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define WALLETMODEL_H
|
#define WALLETMODEL_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class OptionsModel;
|
class OptionsModel;
|
||||||
class AddressTableModel;
|
class AddressTableModel;
|
||||||
@ -52,8 +53,6 @@ public:
|
|||||||
int getNumTransactions() const;
|
int getNumTransactions() const;
|
||||||
EncryptionStatus getEncryptionStatus() const;
|
EncryptionStatus getEncryptionStatus() const;
|
||||||
|
|
||||||
bool isEncrypted() const;
|
|
||||||
|
|
||||||
// Check address for validity
|
// Check address for validity
|
||||||
bool validateAddress(const QString &address);
|
bool validateAddress(const QString &address);
|
||||||
|
|
||||||
@ -71,6 +70,38 @@ public:
|
|||||||
|
|
||||||
// Send coins to a list of recipients
|
// Send coins to a list of recipients
|
||||||
SendCoinsReturn sendCoins(const QList<SendCoinsRecipient> &recipients);
|
SendCoinsReturn sendCoins(const QList<SendCoinsRecipient> &recipients);
|
||||||
|
|
||||||
|
// Wallet encryption
|
||||||
|
bool setWalletEncrypted(bool encrypted, const std::string &passphrase);
|
||||||
|
// Passphrase only needed when unlocking
|
||||||
|
bool setWalletLocked(bool locked, const std::string &passPhrase=std::string());
|
||||||
|
bool changePassphrase(const std::string &oldPass, const std::string &newPass);
|
||||||
|
|
||||||
|
// RAI object for unlocking wallet, returned by requestUnlock()
|
||||||
|
class UnlockContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnlockContext(WalletModel *wallet, bool valid, bool relock);
|
||||||
|
~UnlockContext();
|
||||||
|
|
||||||
|
bool isValid() const { return valid; }
|
||||||
|
|
||||||
|
UnlockContext(const UnlockContext& obj)
|
||||||
|
{ CopyFrom(obj); }
|
||||||
|
private:
|
||||||
|
UnlockContext& operator=(const UnlockContext& rhs)
|
||||||
|
{ CopyFrom(rhs); return *this; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
WalletModel *wallet;
|
||||||
|
bool valid;
|
||||||
|
mutable bool relock; // mutable, as it can be set to false by copying
|
||||||
|
|
||||||
|
void CopyFrom(const UnlockContext& rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
UnlockContext requestUnlock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CWallet *wallet;
|
CWallet *wallet;
|
||||||
|
|
||||||
@ -90,6 +121,7 @@ signals:
|
|||||||
void balanceChanged(qint64 balance, qint64 unconfirmedBalance);
|
void balanceChanged(qint64 balance, qint64 unconfirmedBalance);
|
||||||
void numTransactionsChanged(int count);
|
void numTransactionsChanged(int count);
|
||||||
void encryptionStatusChanged(int status);
|
void encryptionStatusChanged(int status);
|
||||||
|
void requireUnlock();
|
||||||
|
|
||||||
// Asynchronous error notification
|
// Asynchronous error notification
|
||||||
void error(const QString &title, const QString &message);
|
void error(const QString &title, const QString &message);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user