Added Caps Lock check and warning at askpassphrasedialog.
[novacoin.git] / src / qt / askpassphrasedialog.cpp
1 #include "askpassphrasedialog.h"
2 #include "ui_askpassphrasedialog.h"
3
4 #include "guiconstants.h"
5 #include "walletmodel.h"
6
7 #include <QMessageBox>
8 #include <QPushButton>
9 #include <QKeyEvent>
10
11 AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
12     QDialog(parent),
13     ui(new Ui::AskPassphraseDialog),
14     mode(mode),
15     model(0),
16     fCapsLock(false)
17 {
18     ui->setupUi(this);
19     ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
20     ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
21     ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
22     
23     // Setup Caps Lock detection.
24     ui->passEdit1->installEventFilter(this);
25     ui->passEdit2->installEventFilter(this);
26     ui->passEdit3->installEventFilter(this);
27     ui->capsLabel->clear();
28
29     switch(mode)
30     {
31         case Encrypt: // Ask passphrase x2
32             ui->passLabel1->hide();
33             ui->passEdit1->hide();
34             ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>."));
35             setWindowTitle(tr("Encrypt wallet"));
36             break;
37         case Unlock: // Ask passphrase
38             ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
39             ui->passLabel2->hide();
40             ui->passEdit2->hide();
41             ui->passLabel3->hide();
42             ui->passEdit3->hide();
43             setWindowTitle(tr("Unlock wallet"));
44             break;
45         case Decrypt:   // Ask passphrase
46             ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
47             ui->passLabel2->hide();
48             ui->passEdit2->hide();
49             ui->passLabel3->hide();
50             ui->passEdit3->hide();
51             setWindowTitle(tr("Decrypt wallet"));
52             break;
53         case ChangePass: // Ask old passphrase + new passphrase x2
54             setWindowTitle(tr("Change passphrase"));
55             ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
56             break;
57     }
58     resize(minimumSize()); // Get rid of extra space in dialog
59
60     textChanged();
61     connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
62     connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
63     connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
64 }
65
66 AskPassphraseDialog::~AskPassphraseDialog()
67 {
68     // Attempt to overwrite text so that they do not linger around in memory
69     ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
70     ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
71     ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
72     delete ui;
73 }
74
75 void AskPassphraseDialog::setModel(WalletModel *model)
76 {
77     this->model = model;
78 }
79
80 void AskPassphraseDialog::accept()
81 {
82     std::string oldpass, newpass1, newpass2;
83     // TODO: mlock memory / munlock on return so they will not be swapped out, really need "mlockedstring" wrapper class to do this safely
84     oldpass.reserve(MAX_PASSPHRASE_SIZE);
85     newpass1.reserve(MAX_PASSPHRASE_SIZE);
86     newpass2.reserve(MAX_PASSPHRASE_SIZE);
87     oldpass.assign(ui->passEdit1->text().toStdString());
88     newpass1.assign(ui->passEdit2->text().toStdString());
89     newpass2.assign(ui->passEdit3->text().toStdString());
90
91     switch(mode)
92     {
93     case Encrypt: {
94         if(newpass1.empty() || newpass2.empty())
95         {
96             // Cannot encrypt with empty passphrase
97             break;
98         }
99         QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
100                  tr("WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!\nAre you sure you wish to encrypt your wallet?"),
101                  QMessageBox::Yes|QMessageBox::Cancel,
102                  QMessageBox::Cancel);
103         if(retval == QMessageBox::Yes)
104         {
105             if(newpass1 == newpass2)
106             {
107                 if(model->setWalletEncrypted(true, newpass1))
108                 {
109                     QMessageBox::warning(this, tr("Wallet encrypted"),
110                                          tr("Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."));
111                 }
112                 else
113                 {
114                     QMessageBox::critical(this, tr("Wallet encryption failed"),
115                                          tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
116                 }
117                 QDialog::accept(); // Success
118             }
119             else
120             {
121                 QMessageBox::critical(this, tr("Wallet encryption failed"),
122                                      tr("The supplied passphrases do not match."));
123             }
124         }
125         else
126         {
127             QDialog::reject(); // Cancelled
128         }
129         } break;
130     case Unlock:
131         if(!model->setWalletLocked(false, oldpass))
132         {
133             QMessageBox::critical(this, tr("Wallet unlock failed"),
134                                   tr("The passphrase entered for the wallet decryption was incorrect."));
135         }
136         else
137         {
138             QDialog::accept(); // Success
139         }
140         break;
141     case Decrypt:
142         if(!model->setWalletEncrypted(false, oldpass))
143         {
144             QMessageBox::critical(this, tr("Wallet decryption failed"),
145                                   tr("The passphrase entered for the wallet decryption was incorrect."));
146         }
147         else
148         {
149             QDialog::accept(); // Success
150         }
151         break;
152     case ChangePass:
153         if(newpass1 == newpass2)
154         {
155             if(model->changePassphrase(oldpass, newpass1))
156             {
157                 QMessageBox::information(this, tr("Wallet encrypted"),
158                                      tr("Wallet passphrase was succesfully changed."));
159                 QDialog::accept(); // Success
160             }
161             else
162             {
163                 QMessageBox::critical(this, tr("Wallet encryption failed"),
164                                      tr("The passphrase entered for the wallet decryption was incorrect."));
165             }
166         }
167         else
168         {
169             QMessageBox::critical(this, tr("Wallet encryption failed"),
170                                  tr("The supplied passphrases do not match."));
171         }
172         break;
173     }
174 }
175
176 void AskPassphraseDialog::textChanged()
177 {
178     // Validate input, set Ok button to enabled when accepable
179     bool acceptable = false;
180     switch(mode)
181     {
182     case Encrypt: // New passphrase x2
183         acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
184         break;
185     case Unlock: // Old passphrase x1
186     case Decrypt:
187         acceptable = !ui->passEdit1->text().isEmpty();
188         break;
189     case ChangePass: // Old passphrase x1, new passphrase x2
190         acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
191         break;
192     }
193     ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
194 }
195
196 bool AskPassphraseDialog::event(QEvent *event)
197 {
198     // Detect Caps Lock key press.
199     if (event->type() == QEvent::KeyPress) {
200         QKeyEvent *ke = static_cast<QKeyEvent *>(event);
201         if (ke->key() == Qt::Key_CapsLock) {
202             fCapsLock = !fCapsLock;
203         }
204         if (fCapsLock) {
205             ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
206         } else {
207             ui->capsLabel->clear();
208         }
209     }
210     return QWidget::event(event);
211 }
212
213 bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event)
214 {
215     /* Detect Caps Lock. 
216      * There is no good OS-independent way to check a key state in Qt, but we
217      * can detect Caps Lock by checking for the following condition:
218      * Shift key is down and the result is a lower case character, or
219      * Shift key is not down and the result is an upper case character.
220      */
221     if (event->type() == QEvent::KeyPress) {
222         QKeyEvent *ke = static_cast<QKeyEvent *>(event);
223         QString str = ke->text();
224         if (str.length() != 0) {
225             const QChar *psz = str.unicode();
226             bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
227             if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) {
228                 fCapsLock = true;
229                 ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
230             } else if (psz->isLetter()) {
231                 fCapsLock = false;
232                 ui->capsLabel->clear();
233             }
234         }
235     }
236     return false;
237 }