Line data Source code
1 : // Copyright (c) 2011-2013 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include "askpassphrasedialog.h"
6 : #include "ui_askpassphrasedialog.h"
7 :
8 : #include "guiconstants.h"
9 : #include "walletmodel.h"
10 :
11 : #include "support/allocators/secure.h"
12 :
13 : #include <QKeyEvent>
14 : #include <QMessageBox>
15 : #include <QPushButton>
16 :
17 0 : AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
18 : QDialog(parent),
19 0 : ui(new Ui::AskPassphraseDialog),
20 : mode(mode),
21 : model(0),
22 0 : fCapsLock(false)
23 : {
24 0 : ui->setupUi(this);
25 :
26 0 : ui->passEdit1->setMinimumSize(ui->passEdit1->sizeHint());
27 0 : ui->passEdit2->setMinimumSize(ui->passEdit2->sizeHint());
28 0 : ui->passEdit3->setMinimumSize(ui->passEdit3->sizeHint());
29 :
30 0 : ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
31 0 : ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
32 0 : ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
33 :
34 : // Setup Caps Lock detection.
35 0 : ui->passEdit1->installEventFilter(this);
36 0 : ui->passEdit2->installEventFilter(this);
37 0 : ui->passEdit3->installEventFilter(this);
38 :
39 0 : switch(mode)
40 : {
41 : case Encrypt: // Ask passphrase x2
42 0 : ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>."));
43 0 : ui->passLabel1->hide();
44 0 : ui->passEdit1->hide();
45 0 : setWindowTitle(tr("Encrypt wallet"));
46 0 : break;
47 : case Unlock: // Ask passphrase
48 0 : ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
49 0 : ui->passLabel2->hide();
50 0 : ui->passEdit2->hide();
51 0 : ui->passLabel3->hide();
52 0 : ui->passEdit3->hide();
53 0 : setWindowTitle(tr("Unlock wallet"));
54 0 : break;
55 : case Decrypt: // Ask passphrase
56 0 : ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
57 0 : ui->passLabel2->hide();
58 0 : ui->passEdit2->hide();
59 0 : ui->passLabel3->hide();
60 0 : ui->passEdit3->hide();
61 0 : setWindowTitle(tr("Decrypt wallet"));
62 0 : break;
63 : case ChangePass: // Ask old passphrase + new passphrase x2
64 0 : setWindowTitle(tr("Change passphrase"));
65 0 : ui->warningLabel->setText(tr("Enter the old passphrase and new passphrase to the wallet."));
66 0 : break;
67 : }
68 0 : textChanged();
69 0 : connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
70 0 : connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
71 0 : connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
72 0 : }
73 :
74 0 : AskPassphraseDialog::~AskPassphraseDialog()
75 : {
76 : // Attempt to overwrite text so that they do not linger around in memory
77 0 : ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
78 0 : ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
79 0 : ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
80 0 : delete ui;
81 0 : }
82 :
83 0 : void AskPassphraseDialog::setModel(WalletModel *model)
84 : {
85 0 : this->model = model;
86 0 : }
87 :
88 0 : void AskPassphraseDialog::accept()
89 : {
90 : SecureString oldpass, newpass1, newpass2;
91 0 : if(!model)
92 0 : return;
93 0 : oldpass.reserve(MAX_PASSPHRASE_SIZE);
94 0 : newpass1.reserve(MAX_PASSPHRASE_SIZE);
95 0 : newpass2.reserve(MAX_PASSPHRASE_SIZE);
96 : // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
97 : // Alternately, find a way to make this input mlock()'d to begin with.
98 0 : oldpass.assign(ui->passEdit1->text().toStdString().c_str());
99 0 : newpass1.assign(ui->passEdit2->text().toStdString().c_str());
100 0 : newpass2.assign(ui->passEdit3->text().toStdString().c_str());
101 :
102 0 : switch(mode)
103 : {
104 : case Encrypt: {
105 0 : if(newpass1.empty() || newpass2.empty())
106 : {
107 : // Cannot encrypt with empty passphrase
108 : break;
109 : }
110 : QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
111 0 : tr("Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!") + "<br><br>" + tr("Are you sure you wish to encrypt your wallet?"),
112 0 : QMessageBox::Yes|QMessageBox::Cancel,
113 0 : QMessageBox::Cancel);
114 0 : if(retval == QMessageBox::Yes)
115 : {
116 0 : if(newpass1 == newpass2)
117 : {
118 0 : if(model->setWalletEncrypted(true, newpass1))
119 : {
120 : QMessageBox::warning(this, tr("Wallet encrypted"),
121 0 : "<qt>" +
122 : tr("Bitcoin Core will close now to finish the encryption process. "
123 : "Remember that encrypting your wallet cannot fully protect "
124 0 : "your bitcoins from being stolen by malware infecting your computer.") +
125 0 : "<br><br><b>" +
126 : tr("IMPORTANT: Any previous backups you have made of your wallet file "
127 : "should be replaced with the newly generated, encrypted wallet file. "
128 : "For security reasons, previous backups of the unencrypted wallet file "
129 0 : "will become useless as soon as you start using the new, encrypted wallet.") +
130 0 : "</b></qt>");
131 0 : QApplication::quit();
132 : }
133 : else
134 : {
135 : QMessageBox::critical(this, tr("Wallet encryption failed"),
136 0 : tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
137 : }
138 0 : QDialog::accept(); // Success
139 : }
140 : else
141 : {
142 : QMessageBox::critical(this, tr("Wallet encryption failed"),
143 0 : tr("The supplied passphrases do not match."));
144 : }
145 : }
146 : else
147 : {
148 0 : QDialog::reject(); // Cancelled
149 : }
150 : } break;
151 : case Unlock:
152 0 : if(!model->setWalletLocked(false, oldpass))
153 : {
154 : QMessageBox::critical(this, tr("Wallet unlock failed"),
155 0 : tr("The passphrase entered for the wallet decryption was incorrect."));
156 : }
157 : else
158 : {
159 0 : QDialog::accept(); // Success
160 : }
161 : break;
162 : case Decrypt:
163 0 : if(!model->setWalletEncrypted(false, oldpass))
164 : {
165 : QMessageBox::critical(this, tr("Wallet decryption failed"),
166 0 : tr("The passphrase entered for the wallet decryption was incorrect."));
167 : }
168 : else
169 : {
170 0 : QDialog::accept(); // Success
171 : }
172 : break;
173 : case ChangePass:
174 0 : if(newpass1 == newpass2)
175 : {
176 0 : if(model->changePassphrase(oldpass, newpass1))
177 : {
178 : QMessageBox::information(this, tr("Wallet encrypted"),
179 0 : tr("Wallet passphrase was successfully changed."));
180 0 : QDialog::accept(); // Success
181 : }
182 : else
183 : {
184 : QMessageBox::critical(this, tr("Wallet encryption failed"),
185 0 : tr("The passphrase entered for the wallet decryption was incorrect."));
186 : }
187 : }
188 : else
189 : {
190 : QMessageBox::critical(this, tr("Wallet encryption failed"),
191 0 : tr("The supplied passphrases do not match."));
192 : }
193 : break;
194 : }
195 : }
196 :
197 0 : void AskPassphraseDialog::textChanged()
198 : {
199 : // Validate input, set Ok button to enabled when acceptable
200 0 : bool acceptable = false;
201 0 : switch(mode)
202 : {
203 : case Encrypt: // New passphrase x2
204 0 : acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
205 : break;
206 : case Unlock: // Old passphrase x1
207 : case Decrypt:
208 0 : acceptable = !ui->passEdit1->text().isEmpty();
209 0 : break;
210 : case ChangePass: // Old passphrase x1, new passphrase x2
211 0 : acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
212 : break;
213 : }
214 0 : ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
215 0 : }
216 :
217 0 : bool AskPassphraseDialog::event(QEvent *event)
218 : {
219 : // Detect Caps Lock key press.
220 0 : if (event->type() == QEvent::KeyPress) {
221 0 : QKeyEvent *ke = static_cast<QKeyEvent *>(event);
222 0 : if (ke->key() == Qt::Key_CapsLock) {
223 0 : fCapsLock = !fCapsLock;
224 : }
225 0 : if (fCapsLock) {
226 0 : ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
227 : } else {
228 0 : ui->capsLabel->clear();
229 : }
230 : }
231 0 : return QWidget::event(event);
232 : }
233 :
234 0 : bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
235 : {
236 : /* Detect Caps Lock.
237 : * There is no good OS-independent way to check a key state in Qt, but we
238 : * can detect Caps Lock by checking for the following condition:
239 : * Shift key is down and the result is a lower case character, or
240 : * Shift key is not down and the result is an upper case character.
241 : */
242 0 : if (event->type() == QEvent::KeyPress) {
243 0 : QKeyEvent *ke = static_cast<QKeyEvent *>(event);
244 : QString str = ke->text();
245 0 : if (str.length() != 0) {
246 0 : const QChar *psz = str.unicode();
247 0 : bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
248 0 : if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) {
249 0 : fCapsLock = true;
250 0 : ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
251 0 : } else if (psz->isLetter()) {
252 0 : fCapsLock = false;
253 0 : ui->capsLabel->clear();
254 : }
255 0 : }
256 : }
257 0 : return QDialog::eventFilter(object, event);
258 0 : }
|