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