Skip to content

Commit b7bcaf9

Browse files
committed
Wallet encryption part 2: ask passphrase when needed, add menu options
1 parent 3f0816e commit b7bcaf9

16 files changed

+582
-9
lines changed

bitcoin-qt.pro

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ HEADERS += src/qt/bitcoingui.h \
9090
src/qt/sendcoinsentry.h \
9191
src/qt/qvalidatedlineedit.h \
9292
src/qt/bitcoinunits.h \
93-
src/qt/qvaluecombobox.h
93+
src/qt/qvaluecombobox.h \
94+
src/qt/askpassphrasedialog.h
9495
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
9596
src/qt/transactiontablemodel.cpp \
9697
src/qt/addresstablemodel.cpp \
@@ -134,7 +135,8 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
134135
src/qt/sendcoinsentry.cpp \
135136
src/qt/qvalidatedlineedit.cpp \
136137
src/qt/bitcoinunits.cpp \
137-
src/qt/qvaluecombobox.cpp
138+
src/qt/qvaluecombobox.cpp \
139+
src/qt/askpassphrasedialog.cpp
138140

139141
RESOURCES += \
140142
src/qt/bitcoin.qrc
@@ -146,7 +148,8 @@ FORMS += \
146148
src/qt/forms/editaddressdialog.ui \
147149
src/qt/forms/transactiondescdialog.ui \
148150
src/qt/forms/overviewpage.ui \
149-
src/qt/forms/sendcoinsentry.ui
151+
src/qt/forms/sendcoinsentry.ui \
152+
src/qt/forms/askpassphrasedialog.ui
150153

151154
CODECFORTR = UTF-8
152155
# for lrelease/lupdate

doc/assets-attribution.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,10 @@ Designer: Crobbo (forum)
6464
Site: https://bitcointalk.org/index.php?topic=32273.0
6565
License: Public domain
6666

67+
Icon: src/qt/res/icons/key.png
68+
Designer: VisualPharm (Ivan Boyko)
69+
Icon Pack: Must Have
70+
Site: http://findicons.com/icon/51009/key?id=51009
71+
License: Creative Commons Attribution (by)
6772

6873

src/qt/addresstablemodel.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,14 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
267267
else if(type == Receive)
268268
{
269269
// Generate a new address to associate with given label
270+
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
271+
if(!ctx.isValid())
272+
{
273+
// Unlock wallet failed or was cancelled
274+
editStatus = WALLET_UNLOCK_FAILURE;
275+
return QString();
276+
}
277+
270278
strAddress = CBitcoinAddress(wallet->GetOrReuseKeyFromPool()).ToString();
271279
}
272280
else

src/qt/addresstablemodel.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ class AddressTableModel : public QAbstractTableModel
2626

2727
// Return status of last edit/insert operation
2828
enum EditStatus {
29-
OK = 0,
30-
INVALID_ADDRESS = 1,
31-
DUPLICATE_ADDRESS = 2
29+
OK,
30+
INVALID_ADDRESS,
31+
DUPLICATE_ADDRESS,
32+
WALLET_UNLOCK_FAILURE
3233
};
3334

3435
static const QString Send; /* Send addres */

src/qt/askpassphrasedialog.cpp

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#include "askpassphrasedialog.h"
2+
#include "ui_askpassphrasedialog.h"
3+
4+
#include "guiconstants.h"
5+
#include "walletmodel.h"
6+
7+
#include <QMessageBox>
8+
#include <QPushButton>
9+
10+
AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
11+
QDialog(parent),
12+
ui(new Ui::AskPassphraseDialog),
13+
mode(mode),
14+
model(0)
15+
{
16+
ui->setupUi(this);
17+
ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
18+
ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
19+
ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
20+
21+
switch(mode)
22+
{
23+
case Encrypt: // Ask passphrase x2
24+
ui->passLabel1->hide();
25+
ui->passEdit1->hide();
26+
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>."));
27+
setWindowTitle(tr("Encrypt wallet"));
28+
break;
29+
case Unlock: // Ask passphrase
30+
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
31+
ui->passLabel2->hide();
32+
ui->passEdit2->hide();
33+
ui->passLabel3->hide();
34+
ui->passEdit3->hide();
35+
setWindowTitle(tr("Unlock wallet"));
36+
break;
37+
case Decrypt: // Ask passphrase
38+
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
39+
ui->passLabel2->hide();
40+
ui->passEdit2->hide();
41+
ui->passLabel3->hide();
42+
ui->passEdit3->hide();
43+
setWindowTitle(tr("Decrypt wallet"));
44+
break;
45+
case ChangePass: // Ask old passphrase + new passphrase x2
46+
setWindowTitle(tr("Change passphrase"));
47+
ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
48+
break;
49+
}
50+
resize(minimumSize()); // Get rid of extra space in dialog
51+
52+
textChanged();
53+
connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
54+
connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
55+
connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
56+
}
57+
58+
AskPassphraseDialog::~AskPassphraseDialog()
59+
{
60+
// Attempt to overwrite text so that they do not linger around in memory
61+
ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
62+
ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
63+
ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
64+
delete ui;
65+
}
66+
67+
void AskPassphraseDialog::setModel(WalletModel *model)
68+
{
69+
this->model = model;
70+
}
71+
72+
void AskPassphraseDialog::accept()
73+
{
74+
std::string oldpass, newpass1, newpass2;
75+
// TODO: mlock memory / munlock on return so they will not be swapped out, really need "mlockedstring" wrapper class to do this safely
76+
oldpass.reserve(MAX_PASSPHRASE_SIZE);
77+
newpass1.reserve(MAX_PASSPHRASE_SIZE);
78+
newpass2.reserve(MAX_PASSPHRASE_SIZE);
79+
oldpass.assign(ui->passEdit1->text().toStdString());
80+
newpass1.assign(ui->passEdit2->text().toStdString());
81+
newpass2.assign(ui->passEdit3->text().toStdString());
82+
83+
switch(mode)
84+
{
85+
case Encrypt: {
86+
if(newpass1.empty() || newpass2.empty())
87+
{
88+
// Cannot encrypt with empty passphrase
89+
break;
90+
}
91+
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
92+
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?"),
93+
QMessageBox::Yes|QMessageBox::Cancel,
94+
QMessageBox::Cancel);
95+
if(retval == QMessageBox::Yes)
96+
{
97+
if(newpass1 == newpass2)
98+
{
99+
if(model->setWalletEncrypted(true, newpass1))
100+
{
101+
QMessageBox::warning(this, tr("Wallet encrypted"),
102+
tr("Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."));
103+
}
104+
else
105+
{
106+
QMessageBox::critical(this, tr("Wallet encryption failed"),
107+
tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
108+
}
109+
QDialog::accept(); // Success
110+
}
111+
else
112+
{
113+
QMessageBox::critical(this, tr("Wallet encryption failed"),
114+
tr("The supplied passphrases do not match."));
115+
}
116+
}
117+
else
118+
{
119+
QDialog::reject(); // Cancelled
120+
}
121+
} break;
122+
case Unlock:
123+
if(!model->setWalletLocked(false, oldpass))
124+
{
125+
QMessageBox::critical(this, tr("Wallet unlock failed"),
126+
tr("The passphrase entered for the wallet decryption was incorrect."));
127+
}
128+
else
129+
{
130+
QDialog::accept(); // Success
131+
}
132+
break;
133+
case Decrypt:
134+
if(!model->setWalletEncrypted(false, oldpass))
135+
{
136+
QMessageBox::critical(this, tr("Wallet decryption failed"),
137+
tr("The passphrase entered for the wallet decryption was incorrect."));
138+
}
139+
else
140+
{
141+
QDialog::accept(); // Success
142+
}
143+
break;
144+
case ChangePass:
145+
if(newpass1 == newpass2)
146+
{
147+
if(model->changePassphrase(oldpass, newpass1))
148+
{
149+
QMessageBox::information(this, tr("Wallet encrypted"),
150+
tr("Wallet passphrase was succesfully changed."));
151+
QDialog::accept(); // Success
152+
}
153+
else
154+
{
155+
QMessageBox::critical(this, tr("Wallet encryption failed"),
156+
tr("The passphrase entered for the wallet decryption was incorrect."));
157+
}
158+
}
159+
else
160+
{
161+
QMessageBox::critical(this, tr("Wallet encryption failed"),
162+
tr("The supplied passphrases do not match."));
163+
}
164+
break;
165+
}
166+
}
167+
168+
void AskPassphraseDialog::textChanged()
169+
{
170+
// Validate input, set Ok button to enabled when accepable
171+
bool acceptable = false;
172+
switch(mode)
173+
{
174+
case Encrypt: // New passphrase x2
175+
acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
176+
break;
177+
case Unlock: // Old passphrase x1
178+
case Decrypt:
179+
acceptable = !ui->passEdit1->text().isEmpty();
180+
break;
181+
case ChangePass: // Old passphrase x1, new passphrase x2
182+
acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
183+
break;
184+
}
185+
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
186+
}

src/qt/askpassphrasedialog.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef ASKPASSPHRASEDIALOG_H
2+
#define ASKPASSPHRASEDIALOG_H
3+
4+
#include <QDialog>
5+
6+
namespace Ui {
7+
class AskPassphraseDialog;
8+
}
9+
10+
class WalletModel;
11+
12+
class AskPassphraseDialog : public QDialog
13+
{
14+
Q_OBJECT
15+
16+
public:
17+
enum Mode {
18+
Encrypt, // Ask passphrase x2
19+
Unlock, // Ask passphrase
20+
ChangePass, // Ask old passphrase + new passphrase x2
21+
Decrypt // Ask passphrase
22+
};
23+
24+
explicit AskPassphraseDialog(Mode mode, QWidget *parent = 0);
25+
~AskPassphraseDialog();
26+
27+
void accept();
28+
29+
void setModel(WalletModel *model);
30+
31+
private:
32+
Ui::AskPassphraseDialog *ui;
33+
Mode mode;
34+
WalletModel *model;
35+
36+
private slots:
37+
void textChanged();
38+
};
39+
40+
#endif // ASKPASSPHRASEDIALOG_H

src/qt/bitcoin.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<file alias="tx_inout">res/icons/tx_inout.png</file>
3737
<file alias="lock_closed">res/icons/lock_closed.png</file>
3838
<file alias="lock_open">res/icons/lock_open.png</file>
39+
<file alias="key">res/icons/key.png</file>
3940
</qresource>
4041
<qresource prefix="/images">
4142
<file alias="about">res/images/about.png</file>

0 commit comments

Comments
 (0)