1 // Copyright (c) 2011-2016 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.
5 #if defined(HAVE_CONFIG_H)
6 #include <config/bitcoin-config.h>
9 #include <qt/askpassphrasedialog.h>
10 #include <qt/forms/ui_askpassphrasedialog.h>
12 #include <qt/guiconstants.h>
13 #include <qt/walletmodel.h>
15 #include <support/allocators/secure.h>
18 #include <QMessageBox>
19 #include <QPushButton>
21 AskPassphraseDialog::AskPassphraseDialog(Mode _mode
, QWidget
*parent
) :
23 ui(new Ui::AskPassphraseDialog
),
30 ui
->passEdit1
->setMinimumSize(ui
->passEdit1
->sizeHint());
31 ui
->passEdit2
->setMinimumSize(ui
->passEdit2
->sizeHint());
32 ui
->passEdit3
->setMinimumSize(ui
->passEdit3
->sizeHint());
34 ui
->passEdit1
->setMaxLength(MAX_PASSPHRASE_SIZE
);
35 ui
->passEdit2
->setMaxLength(MAX_PASSPHRASE_SIZE
);
36 ui
->passEdit3
->setMaxLength(MAX_PASSPHRASE_SIZE
);
38 // Setup Caps Lock detection.
39 ui
->passEdit1
->installEventFilter(this);
40 ui
->passEdit2
->installEventFilter(this);
41 ui
->passEdit3
->installEventFilter(this);
45 case Encrypt
: // Ask passphrase x2
46 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>."));
47 ui
->passLabel1
->hide();
48 ui
->passEdit1
->hide();
49 setWindowTitle(tr("Encrypt wallet"));
51 case Unlock
: // Ask passphrase
52 ui
->warningLabel
->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
53 ui
->passLabel2
->hide();
54 ui
->passEdit2
->hide();
55 ui
->passLabel3
->hide();
56 ui
->passEdit3
->hide();
57 setWindowTitle(tr("Unlock wallet"));
59 case Decrypt
: // Ask passphrase
60 ui
->warningLabel
->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
61 ui
->passLabel2
->hide();
62 ui
->passEdit2
->hide();
63 ui
->passLabel3
->hide();
64 ui
->passEdit3
->hide();
65 setWindowTitle(tr("Decrypt wallet"));
67 case ChangePass
: // Ask old passphrase + new passphrase x2
68 setWindowTitle(tr("Change passphrase"));
69 ui
->warningLabel
->setText(tr("Enter the old passphrase and new passphrase to the wallet."));
73 connect(ui
->toggleShowPasswordButton
, SIGNAL(toggled(bool)), this, SLOT(toggleShowPassword(bool)));
74 connect(ui
->passEdit1
, SIGNAL(textChanged(QString
)), this, SLOT(textChanged()));
75 connect(ui
->passEdit2
, SIGNAL(textChanged(QString
)), this, SLOT(textChanged()));
76 connect(ui
->passEdit3
, SIGNAL(textChanged(QString
)), this, SLOT(textChanged()));
79 AskPassphraseDialog::~AskPassphraseDialog()
81 secureClearPassFields();
85 void AskPassphraseDialog::setModel(WalletModel
*_model
)
90 void AskPassphraseDialog::accept()
92 SecureString oldpass
, newpass1
, newpass2
;
95 oldpass
.reserve(MAX_PASSPHRASE_SIZE
);
96 newpass1
.reserve(MAX_PASSPHRASE_SIZE
);
97 newpass2
.reserve(MAX_PASSPHRASE_SIZE
);
98 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
99 // Alternately, find a way to make this input mlock()'d to begin with.
100 oldpass
.assign(ui
->passEdit1
->text().toStdString().c_str());
101 newpass1
.assign(ui
->passEdit2
->text().toStdString().c_str());
102 newpass2
.assign(ui
->passEdit3
->text().toStdString().c_str());
104 secureClearPassFields();
109 if(newpass1
.empty() || newpass2
.empty())
111 // Cannot encrypt with empty passphrase
114 QMessageBox::StandardButton retval
= QMessageBox::question(this, tr("Confirm wallet encryption"),
115 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?"),
116 QMessageBox::Yes
|QMessageBox::Cancel
,
117 QMessageBox::Cancel
);
118 if(retval
== QMessageBox::Yes
)
120 if(newpass1
== newpass2
)
122 if(model
->setWalletEncrypted(true, newpass1
))
124 QMessageBox::warning(this, tr("Wallet encrypted"),
126 tr("%1 will close now to finish the encryption process. "
127 "Remember that encrypting your wallet cannot fully protect "
128 "your bitcoins from being stolen by malware infecting your computer.").arg(tr(PACKAGE_NAME
)) +
130 tr("IMPORTANT: Any previous backups you have made of your wallet file "
131 "should be replaced with the newly generated, encrypted wallet file. "
132 "For security reasons, previous backups of the unencrypted wallet file "
133 "will become useless as soon as you start using the new, encrypted wallet.") +
135 QApplication::quit();
139 QMessageBox::critical(this, tr("Wallet encryption failed"),
140 tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
142 QDialog::accept(); // Success
146 QMessageBox::critical(this, tr("Wallet encryption failed"),
147 tr("The supplied passphrases do not match."));
152 QDialog::reject(); // Cancelled
156 if(!model
->setWalletLocked(false, oldpass
))
158 QMessageBox::critical(this, tr("Wallet unlock failed"),
159 tr("The passphrase entered for the wallet decryption was incorrect."));
163 QDialog::accept(); // Success
167 if(!model
->setWalletEncrypted(false, oldpass
))
169 QMessageBox::critical(this, tr("Wallet decryption failed"),
170 tr("The passphrase entered for the wallet decryption was incorrect."));
174 QDialog::accept(); // Success
178 if(newpass1
== newpass2
)
180 if(model
->changePassphrase(oldpass
, newpass1
))
182 QMessageBox::information(this, tr("Wallet encrypted"),
183 tr("Wallet passphrase was successfully changed."));
184 QDialog::accept(); // Success
188 QMessageBox::critical(this, tr("Wallet encryption failed"),
189 tr("The passphrase entered for the wallet decryption was incorrect."));
194 QMessageBox::critical(this, tr("Wallet encryption failed"),
195 tr("The supplied passphrases do not match."));
201 void AskPassphraseDialog::textChanged()
203 // Validate input, set Ok button to enabled when acceptable
204 bool acceptable
= false;
207 case Encrypt
: // New passphrase x2
208 acceptable
= !ui
->passEdit2
->text().isEmpty() && !ui
->passEdit3
->text().isEmpty();
210 case Unlock
: // Old passphrase x1
212 acceptable
= !ui
->passEdit1
->text().isEmpty();
214 case ChangePass
: // Old passphrase x1, new passphrase x2
215 acceptable
= !ui
->passEdit1
->text().isEmpty() && !ui
->passEdit2
->text().isEmpty() && !ui
->passEdit3
->text().isEmpty();
218 ui
->buttonBox
->button(QDialogButtonBox::Ok
)->setEnabled(acceptable
);
221 bool AskPassphraseDialog::event(QEvent
*event
)
223 // Detect Caps Lock key press.
224 if (event
->type() == QEvent::KeyPress
) {
225 QKeyEvent
*ke
= static_cast<QKeyEvent
*>(event
);
226 if (ke
->key() == Qt::Key_CapsLock
) {
227 fCapsLock
= !fCapsLock
;
230 ui
->capsLabel
->setText(tr("Warning: The Caps Lock key is on!"));
232 ui
->capsLabel
->clear();
235 return QWidget::event(event
);
238 void AskPassphraseDialog::toggleShowPassword(bool show
)
240 ui
->toggleShowPasswordButton
->setDown(show
);
241 const auto mode
= show
? QLineEdit::Normal
: QLineEdit::Password
;
242 ui
->passEdit1
->setEchoMode(mode
);
243 ui
->passEdit2
->setEchoMode(mode
);
244 ui
->passEdit3
->setEchoMode(mode
);
247 bool AskPassphraseDialog::eventFilter(QObject
*object
, QEvent
*event
)
250 * There is no good OS-independent way to check a key state in Qt, but we
251 * can detect Caps Lock by checking for the following condition:
252 * Shift key is down and the result is a lower case character, or
253 * Shift key is not down and the result is an upper case character.
255 if (event
->type() == QEvent::KeyPress
) {
256 QKeyEvent
*ke
= static_cast<QKeyEvent
*>(event
);
257 QString str
= ke
->text();
258 if (str
.length() != 0) {
259 const QChar
*psz
= str
.unicode();
260 bool fShift
= (ke
->modifiers() & Qt::ShiftModifier
) != 0;
261 if ((fShift
&& *psz
>= 'a' && *psz
<= 'z') || (!fShift
&& *psz
>= 'A' && *psz
<= 'Z')) {
263 ui
->capsLabel
->setText(tr("Warning: The Caps Lock key is on!"));
264 } else if (psz
->isLetter()) {
266 ui
->capsLabel
->clear();
270 return QDialog::eventFilter(object
, event
);
273 static void SecureClearQLineEdit(QLineEdit
* edit
)
275 // Attempt to overwrite text so that they do not linger around in memory
276 edit
->setText(QString(" ").repeated(edit
->text().size()));
280 void AskPassphraseDialog::secureClearPassFields()
282 SecureClearQLineEdit(ui
->passEdit1
);
283 SecureClearQLineEdit(ui
->passEdit2
);
284 SecureClearQLineEdit(ui
->passEdit3
);