PRCYCoin  2.0.0.7rc1
P2P Digital Currency
askpassphrasedialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2014 The Bitcoin developers
2 // Copyright (c) 2014-2015 The Dash developers
3 // Copyright (c) 2015-2018 The PIVX developers
4 // Copyright (c) 2018-2020 The DAPS Project developers
5 // Distributed under the MIT/X11 software license, see the accompanying
6 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 
8 #include "askpassphrasedialog.h"
9 #include "ui_askpassphrasedialog.h"
10 
11 #include "guiconstants.h"
12 #include "walletmodel.h"
13 
14 #include "allocators.h"
15 
16 #include <QKeyEvent>
17 #include <QMessageBox>
18 #include <QPushButton>
19 
20 AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model, Context context) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint),
21  ui(new Ui::AskPassphraseDialog),
22  mode(mode),
23  model(model),
24  context(context),
25  fCapsLock(false)
26 {
27  ui->setupUi(this);
28 
29  ui->passEdit1->setMinimumSize(ui->passEdit1->sizeHint());
30  ui->passEdit2->setMinimumSize(ui->passEdit2->sizeHint());
31  ui->passEdit3->setMinimumSize(ui->passEdit3->sizeHint());
32 
33  ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
34  ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
35  ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
36 
37  // Setup Caps Lock detection.
38  ui->passEdit1->installEventFilter(this);
39  ui->passEdit2->installEventFilter(this);
40  ui->passEdit3->installEventFilter(this);
41 
42  this->model = model;
43 
44  switch (mode) {
45  case Mode::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"));
50  break;
51  ui->stakingCheckBox->setChecked(false);
52  ui->stakingCheckBox->hide();
54  case Mode::Unlock: // Ask passphrase
55  ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.<br/><br/>(Wallet may appear not responding as it rescans for all transactions)<br/><br/>"));
56  ui->warningLabel->setAlignment(Qt::AlignHCenter);
57  ui->passLabel2->hide();
58  ui->passEdit2->hide();
59  ui->passLabel3->hide();
60  ui->passEdit3->hide();
61  setWindowTitle(tr("Unlock Wallet"));
62  break;
63  case Mode::Decrypt: // Ask passphrase
64  ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
65  ui->passLabel2->hide();
66  ui->passEdit2->hide();
67  ui->passLabel3->hide();
68  ui->passEdit3->hide();
69  setWindowTitle(tr("Decrypt Wallet"));
70  break;
71  case Mode::ChangePass: // Ask old passphrase + new passphrase x2
72  setWindowTitle(tr("Change Passphrase"));
73  ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
74  break;
75  }
76 
77  // Set checkbox "For staking only" depending on from where we were called
79  ui->stakingCheckBox->setChecked(true);
80  }
81  else {
82  ui->stakingCheckBox->setChecked(false);
83  }
84 
85  // It doesn't make sense to show the checkbox for sending PRCY because you wouldn't check it anyway.
86  if (context == Context::Send) {
87  ui->stakingCheckBox->hide();
88  }
89 
90  textChanged();
91  connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
92  connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
93  connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
94  connect(ui->showPassphraseCheckBox, SIGNAL(clicked()), this, SLOT(on_showPassphraseCheckBox_clicked()));
95 }
96 
98 {
99  // Attempt to overwrite text so that they do not linger around in memory
100  ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
101  ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
102  ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
103  delete ui;
104 }
105 
107 {
108  SecureString oldpass, newpass1, newpass2;
109  if (!model)
110  return;
111  oldpass.reserve(MAX_PASSPHRASE_SIZE);
112  newpass1.reserve(MAX_PASSPHRASE_SIZE);
113  newpass2.reserve(MAX_PASSPHRASE_SIZE);
114  // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
115  // Alternately, find a way to make this input mlock()'d to begin with.
116  oldpass.assign(ui->passEdit1->text().toStdString().c_str());
117  newpass1.assign(ui->passEdit2->text().toStdString().c_str());
118  newpass2.assign(ui->passEdit3->text().toStdString().c_str());
119 
120  switch (mode) {
121  case Mode::Encrypt: {
122  if (newpass1.empty() || newpass2.empty()) {
123  // Cannot encrypt with empty passphrase
124  break;
125  }
126  QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm Wallet Encryption"),
127  tr("Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR COINS</b>!") + "<br><br>" + tr("Are you sure you wish to encrypt your wallet?"),
128  QMessageBox::Yes | QMessageBox::Cancel,
129  QMessageBox::Cancel);
130  if (retval == QMessageBox::Yes) {
131  if (newpass1 == newpass2) {
132  if (model->setWalletEncrypted(true, newpass1)) {
133  QMessageBox::warning(this, tr("Wallet Encrypted"),
134  "<qt>" +
135  tr("PRCY will close now to finish the encryption process. "
136  "Remember that encrypting your wallet cannot fully protect "
137  "your PRCYs from being stolen by malware infecting your computer.") +
138  "<br><br><b>" +
139  tr("IMPORTANT: Any previous backups you have made of your wallet file "
140  "should be replaced with the newly generated, encrypted wallet file. "
141  "For security reasons, previous backups of the unencrypted wallet file "
142  "will become useless as soon as you start using the new, encrypted wallet.") +
143  "</b></qt>");
144  QApplication::quit();
145  } else {
146  QMessageBox msgBox;
147  msgBox.setWindowTitle("Wallet Encryption Failed");
148  msgBox.setText("Wallet encryption failed due to an internal error. Your wallet was not encrypted. Please try again.");
149  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
150  msgBox.setIcon(QMessageBox::Critical);
151  msgBox.exec();
152  }
153  QDialog::accept(); // Success
154  } else {
155  QMessageBox msgBox;
156  msgBox.setWindowTitle("Wallet Encryption Failed");
157  msgBox.setText("The supplied passphrases do not match. Please try again.");
158  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
159  msgBox.setIcon(QMessageBox::Critical);
160  msgBox.exec();
161  }
162  } else {
163  QDialog::reject(); // Cancelled
164  }
165  } break;
166  case Mode::UnlockStaking:
167  case Mode::Unlock:
168  if (!model->setWalletLocked(false, oldpass, ui->stakingCheckBox->isChecked())) {
169  QMessageBox msgBox;
170  msgBox.setWindowTitle("Wallet Unlock Failed");
171  msgBox.setText("The passphrase entered for the wallet unlock was incorrect. Please try again.");
172  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
173  msgBox.setIcon(QMessageBox::Critical);
174  msgBox.exec();
175  } else {
176  QDialog::accept(); // Success
177  }
178  break;
179  case Mode::Decrypt:
180  if (!model->setWalletEncrypted(false, oldpass)) {
181  QMessageBox msgBox;
182  msgBox.setWindowTitle("Wallet Decryption Failed");
183  msgBox.setText("The passphrase entered for the wallet decryption was incorrect. Please try again.");
184  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
185  msgBox.setIcon(QMessageBox::Critical);
186  msgBox.exec();
187  } else {
188  QDialog::accept(); // Success
189  }
190  break;
191  case Mode::ChangePass:
192  if (newpass1 == newpass2) {
193  if (model->changePassphrase(oldpass, newpass1)) {
194  QMessageBox msgBox;
195  msgBox.setWindowTitle("Passphrase Change Successful");
196  msgBox.setText("Wallet passphrase was successfully changed.\nPlease remember your passphrase as there is no way to recover it.");
197  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
198  msgBox.setIcon(QMessageBox::Information);
199  msgBox.exec();
200  QDialog::accept(); // Success
201  } else {
202  QMessageBox msgBox;
203  msgBox.setWindowTitle("Wallet Encryption Failed");
204  msgBox.setText("The passphrase entered for the wallet decryption was incorrect. Please try again.");
205  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
206  msgBox.setIcon(QMessageBox::Critical);
207  msgBox.exec();
208  }
209  } else {
210  QMessageBox msgBox;
211  msgBox.setWindowTitle("Wallet Encryption Failed");
212  msgBox.setText("The supplied passphrases do not match. Please try again.");
213  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
214  msgBox.setIcon(QMessageBox::Critical);
215  msgBox.exec();
216  }
217  break;
218  }
219 }
220 
222 {
223  // Validate input, set Ok button to enabled when acceptable
224  bool acceptable = false;
225  switch (mode) {
226  case Mode::Encrypt: // New passphrase x2
227  acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
228  break;
229  case Mode::UnlockStaking: // Old passphrase x1
230  case Mode::Unlock: // Old passphrase x1
231  case Mode::Decrypt:
232  acceptable = !ui->passEdit1->text().isEmpty();
233  break;
234  case Mode::ChangePass: // Old passphrase x1, new passphrase x2
235  acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
236  break;
237  }
238  ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
239 }
240 
241 bool AskPassphraseDialog::event(QEvent* event)
242 {
243  // Detect Caps Lock key press.
244  if (event->type() == QEvent::KeyPress) {
245  QKeyEvent* ke = static_cast<QKeyEvent*>(event);
246  if (ke->key() == Qt::Key_CapsLock) {
247  fCapsLock = !fCapsLock;
248  }
249  if (fCapsLock) {
250  ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
251  } else {
252  ui->capsLabel->clear();
253  }
254  }
255  return QWidget::event(event);
256 }
257 
258 bool AskPassphraseDialog::eventFilter(QObject* object, QEvent* event)
259 {
260  /* Detect Caps Lock.
261  * There is no good OS-independent way to check a key state in Qt, but we
262  * can detect Caps Lock by checking for the following condition:
263  * Shift key is down and the result is a lower case character, or
264  * Shift key is not down and the result is an upper case character.
265  */
266  if (event->type() == QEvent::KeyPress) {
267  QKeyEvent* ke = static_cast<QKeyEvent*>(event);
268  QString str = ke->text();
269  if (str.length() != 0) {
270  const QChar* psz = str.unicode();
271  bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
272  if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) {
273  fCapsLock = true;
274  ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
275  } else if (psz->isLetter()) {
276  fCapsLock = false;
277  ui->capsLabel->clear();
278  }
279  }
280  }
281  return QDialog::eventFilter(object, event);
282 }
283 
285 {
286  ui->passEdit1->setEchoMode(ui->showPassphraseCheckBox->checkState() == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password );
287  ui->passEdit2->setEchoMode(ui->showPassphraseCheckBox->checkState() == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password );
288  ui->passEdit3->setEchoMode(ui->showPassphraseCheckBox->checkState() == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password );
289 }
290 
WalletModel::changePassphrase
bool changePassphrase(const SecureString &oldPass, const SecureString &newPass)
Definition: walletmodel.cpp:425
WalletModel
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:102
AskPassphraseDialog::event
bool event(QEvent *event)
Definition: askpassphrasedialog.cpp:241
AskPassphraseDialog::Context
Context
Definition: askpassphrasedialog.h:34
walletmodel.h
AskPassphraseDialog::Context::Unlock_Menu
@ Unlock_Menu
AskPassphraseDialog::~AskPassphraseDialog
~AskPassphraseDialog()
Definition: askpassphrasedialog.cpp:97
AskPassphraseDialog
Multifunctional dialog to ask for passphrases.
Definition: askpassphrasedialog.h:19
AskPassphraseDialog::Mode::Unlock
@ Unlock
Ask passphrase and unlock.
AskPassphraseDialog::Mode::Decrypt
@ Decrypt
Ask passphrase and decrypt wallet.
AskPassphraseDialog::fCapsLock
bool fCapsLock
Definition: askpassphrasedialog.h:56
AskPassphraseDialog::context
Context context
Definition: askpassphrasedialog.h:55
AskPassphraseDialog::on_showPassphraseCheckBox_clicked
void on_showPassphraseCheckBox_clicked()
Definition: askpassphrasedialog.cpp:284
SecureString
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: allocators.h:262
allocators.h
AskPassphraseDialog::model
WalletModel * model
Definition: askpassphrasedialog.h:54
AskPassphraseDialog::AskPassphraseDialog
AskPassphraseDialog(Mode mode, QWidget *parent, WalletModel *model, Context context)
Definition: askpassphrasedialog.cpp:20
AskPassphraseDialog::textChanged
void textChanged()
Definition: askpassphrasedialog.cpp:221
AskPassphraseDialog::eventFilter
bool eventFilter(QObject *object, QEvent *event)
Definition: askpassphrasedialog.cpp:258
AskPassphraseDialog::Mode::Encrypt
@ Encrypt
Ask passphrase twice and encrypt.
AskPassphraseDialog::Mode::ChangePass
@ ChangePass
Ask old passphrase + new passphrase twice.
Ui
Definition: 2faconfirmdialog.h:7
WalletModel::setWalletEncrypted
bool setWalletEncrypted(bool encrypted, const SecureString &passphrase)
Definition: walletmodel.cpp:386
AskPassphraseDialog::ui
Ui::AskPassphraseDialog * ui
Definition: askpassphrasedialog.h:52
guiconstants.h
AskPassphraseDialog::Context::BIP_38
@ BIP_38
Send PRCY.
AskPassphraseDialog::accept
void accept()
Definition: askpassphrasedialog.cpp:106
WalletModel::setWalletLocked
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString(), bool stakingOnly=false)
Definition: walletmodel.cpp:397
AddressTablePriv::parent
AddressTableModel * parent
Definition: addresstablemodel.cpp:77
AskPassphraseDialog::mode
Mode mode
Definition: askpassphrasedialog.h:53
GUIUtil::loadStyleSheet
QString loadStyleSheet()
Load global CSS theme.
Definition: guiutil.cpp:721
AskPassphraseDialog::Mode
Mode
Definition: askpassphrasedialog.h:24
askpassphrasedialog.h
AskPassphraseDialog::Mode::UnlockStaking
@ UnlockStaking
Ask passphrase and unlock only for staking.
AskPassphraseDialog::Context::Send
@ Send
Change passphrase.