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