Bitcoin Core 32.99.0
P2P Digital Currency
askpassphrasedialog.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present 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
6#include <qt/forms/ui_askpassphrasedialog.h>
7
8#include <qt/guiconstants.h>
9#include <qt/guiutil.h>
10#include <qt/walletmodel.h>
11
13#include <wallet/types.h>
14
15#include <QKeyEvent>
16#include <QMessageBox>
17#include <QPushButton>
18
19AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureString* passphrase_out) :
20 QDialog(parent, GUIUtil::dialog_flags),
21 ui(new Ui::AskPassphraseDialog),
22 mode(_mode),
23 m_passphrase_out(passphrase_out)
24{
25 ui->setupUi(this);
26
27 ui->passEdit1->setMinimumSize(ui->passEdit1->sizeHint());
28 ui->passEdit2->setMinimumSize(ui->passEdit2->sizeHint());
29 ui->passEdit3->setMinimumSize(ui->passEdit3->sizeHint());
30
31 ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
32 ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
33 ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
34
35 // Setup Caps Lock detection.
36 ui->passEdit1->installEventFilter(this);
37 ui->passEdit2->installEventFilter(this);
38 ui->passEdit3->installEventFilter(this);
39
40 switch(mode)
41 {
42 case Encrypt: // Ask passphrase x2
43 ui->warningLabel->setText(tr("Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>."));
44 ui->passLabel1->hide();
45 ui->passEdit1->hide();
46 setWindowTitle(tr("Encrypt wallet"));
47 break;
48 case UnlockMigration:
49 case Unlock: // Ask passphrase
50 ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
51 ui->passLabel2->hide();
52 ui->passEdit2->hide();
53 ui->passLabel3->hide();
54 ui->passEdit3->hide();
55 setWindowTitle(tr("Unlock wallet"));
56 break;
57 case ChangePass: // Ask old passphrase + new passphrase x2
58 setWindowTitle(tr("Change passphrase"));
59 ui->warningLabel->setText(tr("Enter the old passphrase and new passphrase for the wallet."));
60 break;
61 }
63 connect(ui->toggleShowPasswordButton, &QPushButton::toggled, this, &AskPassphraseDialog::toggleShowPassword);
64 connect(ui->passEdit1, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged);
65 connect(ui->passEdit2, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged);
66 connect(ui->passEdit3, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged);
67
69}
70
72{
74 delete ui;
75}
76
78{
79 this->model = _model;
80}
81
83{
84 SecureString oldpass, newpass1, newpass2;
85 if (!model && mode != Encrypt && mode != UnlockMigration)
86 return;
87 oldpass.reserve(MAX_PASSPHRASE_SIZE);
88 newpass1.reserve(MAX_PASSPHRASE_SIZE);
89 newpass2.reserve(MAX_PASSPHRASE_SIZE);
90
91 oldpass.assign(std::string_view{ui->passEdit1->text().toStdString()});
92 newpass1.assign(std::string_view{ui->passEdit2->text().toStdString()});
93 newpass2.assign(std::string_view{ui->passEdit3->text().toStdString()});
94
96
97 switch(mode)
98 {
99 case Encrypt: {
100 if(newpass1.empty() || newpass2.empty())
101 {
102 // Cannot encrypt with empty passphrase
103 break;
104 }
105 QMessageBox msgBoxConfirm(QMessageBox::Question,
106 tr("Confirm wallet encryption"),
107 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?"),
108 QMessageBox::Cancel | QMessageBox::Yes, this);
109 msgBoxConfirm.button(QMessageBox::Yes)->setText(tr("Continue"));
110 msgBoxConfirm.button(QMessageBox::Cancel)->setText(tr("Back"));
111 msgBoxConfirm.setDefaultButton(QMessageBox::Cancel);
112 QMessageBox::StandardButton retval = (QMessageBox::StandardButton)msgBoxConfirm.exec();
113 if(retval == QMessageBox::Yes)
114 {
115 if(newpass1 == newpass2)
116 {
117 QString encryption_reminder = tr("Remember that encrypting your wallet cannot fully protect "
118 "your bitcoins from being stolen by malware infecting your computer.");
119 if (m_passphrase_out) {
120 m_passphrase_out->assign(newpass1);
121 QMessageBox msgBoxWarning(QMessageBox::Warning,
122 tr("Wallet to be encrypted"),
123 "<qt>" +
124 tr("Your wallet is about to be encrypted. ") + encryption_reminder + " " +
125 tr("Are you sure you wish to encrypt your wallet?") +
126 "</b></qt>",
127 QMessageBox::Cancel | QMessageBox::Yes, this);
128 msgBoxWarning.setDefaultButton(QMessageBox::Cancel);
129 QMessageBox::StandardButton retval = (QMessageBox::StandardButton)msgBoxWarning.exec();
130 if (retval == QMessageBox::Cancel) {
131 QDialog::reject();
132 return;
133 }
134 } else {
135 assert(model != nullptr);
136 if (model->setWalletEncrypted(newpass1)) {
137 QMessageBox::warning(this, tr("Wallet encrypted"),
138 "<qt>" +
139 tr("Your wallet is now encrypted. ") + encryption_reminder +
140 "<br><br><b>" +
141 tr("IMPORTANT: Any previous backups you have made of your wallet file "
142 "should be replaced with the newly generated, encrypted wallet file. "
143 "For security reasons, previous backups of the unencrypted wallet file "
144 "will become useless as soon as you start using the new, encrypted wallet.") +
145 "</b></qt>");
146 } else {
147 QMessageBox::critical(this, tr("Wallet encryption failed"),
148 tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
149 }
150 }
151 QDialog::accept(); // Success
152 }
153 else
154 {
155 QMessageBox::critical(this, tr("Wallet encryption failed"),
156 tr("The supplied passphrases do not match."));
157 }
158 }
159 } break;
160 case Unlock:
161 try {
162 if (auto unlocked{model->wallet().unlock(oldpass)}; !unlocked) {
163 QMessageBox::critical(this, tr("Wallet unlock failed"), QString::fromStdString(unlocked.error().message.translated));
164 } else {
165 if (m_passphrase_out) {
166 m_passphrase_out->assign(oldpass);
167 }
168 QDialog::accept(); // Success
169 }
170 } catch (const std::runtime_error& e) {
171 QMessageBox::critical(this, tr("Wallet unlock failed"), e.what());
172 }
173 break;
174 case UnlockMigration:
175 Assume(m_passphrase_out)->assign(oldpass);
176 QDialog::accept();
177 break;
178 case ChangePass:
179 if(newpass1 == newpass2)
180 {
181 if (auto changed{model->changePassphrase(oldpass, newpass1)}) {
182 QMessageBox::information(this, tr("Wallet encrypted"),
183 tr("Wallet passphrase was successfully changed."));
184 QDialog::accept(); // Success
185 } else {
186 QMessageBox::critical(this, tr("Passphrase change failed"), QString::fromStdString(changed.error().message.translated));
187 }
188 }
189 else
190 {
191 QMessageBox::critical(this, tr("Wallet encryption failed"),
192 tr("The supplied passphrases do not match."));
193 }
194 break;
195 }
196}
197
199{
200 // Validate input, set Ok button to enabled when acceptable
201 bool acceptable = false;
202 switch(mode)
203 {
204 case Encrypt: // New passphrase x2
205 acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
206 break;
207 case UnlockMigration:
208 case Unlock: // Old passphrase x1
209 acceptable = !ui->passEdit1->text().isEmpty();
210 break;
211 case ChangePass: // Old passphrase x1, new passphrase x2
212 acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
213 break;
214 }
215 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
216}
217
218bool AskPassphraseDialog::event(QEvent *event)
219{
220 // Detect Caps Lock key press.
221 if (event->type() == QEvent::KeyPress) {
222 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
223 if (ke->key() == Qt::Key_CapsLock) {
225 }
226 if (fCapsLock) {
227 ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
228 } else {
229 ui->capsLabel->clear();
230 }
231 }
232 return QWidget::event(event);
233}
234
236{
237 ui->toggleShowPasswordButton->setDown(show);
238 const auto mode = show ? QLineEdit::Normal : QLineEdit::Password;
239 ui->passEdit1->setEchoMode(mode);
240 ui->passEdit2->setEchoMode(mode);
241 ui->passEdit3->setEchoMode(mode);
242}
243
244bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
245{
246 /* Detect Caps Lock.
247 * There is no good OS-independent way to check a key state in Qt, but we
248 * can detect Caps Lock by checking for the following condition:
249 * Shift key is down and the result is a lower case character, or
250 * Shift key is not down and the result is an upper case character.
251 */
252 if (event->type() == QEvent::KeyPress) {
253 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
254 QString str = ke->text();
255 if (str.length() != 0) {
256 const QChar *psz = str.unicode();
257 bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
258 if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) {
259 fCapsLock = true;
260 ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
261 } else if (psz->isLetter()) {
262 fCapsLock = false;
263 ui->capsLabel->clear();
264 }
265 }
266 }
267 return QDialog::eventFilter(object, event);
268}
269
270static void SecureClearQLineEdit(QLineEdit* edit)
271{
272 // Attempt to overwrite text so that they do not linger around in memory
273 edit->setText(QString(" ").repeated(edit->text().size()));
274 edit->clear();
275}
276
278{
279 SecureClearQLineEdit(ui->passEdit1);
280 SecureClearQLineEdit(ui->passEdit2);
281 SecureClearQLineEdit(ui->passEdit3);
282}
static void SecureClearQLineEdit(QLineEdit *edit)
#define Assume(val)
Assume is the identity function.
Definition: check.h:128
Multifunctional dialog to ask for passphrases.
SecureString * m_passphrase_out
AskPassphraseDialog(Mode mode, QWidget *parent, SecureString *passphrase_out=nullptr)
void setModel(WalletModel *model)
bool eventFilter(QObject *object, QEvent *event) override
bool event(QEvent *event) override
@ Unlock
Ask passphrase and unlock.
@ Encrypt
Ask passphrase twice and encrypt.
@ ChangePass
Ask old passphrase + new passphrase twice.
@ UnlockMigration
Ask passphrase for unlocking during migration.
Ui::AskPassphraseDialog * ui
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:49
util::Expected< void, wallet::WalletError > changePassphrase(const SecureString &oldPass, const SecureString &newPass)
bool setWalletEncrypted(const SecureString &passphrase)
interfaces::Wallet & wallet() const
Definition: walletmodel.h:136
constexpr int MAX_PASSPHRASE_SIZE
Definition: guiconstants.h:20
Utility functions used by the Bitcoin Qt UI.
Definition: bitcoingui.h:58
void handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:426
constexpr auto dialog_flags
Definition: guiutil.h:60
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:53
assert(!tx.IsCoinBase())
is a home for public enum and struct type definitions that are used by internally by wallet code,...