f5161694605bb08c86b16b2a627413f96eed6fc5
[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     SecureString oldpass, newpass1, newpass2;
83     if(!model)
84         return;
85     oldpass.reserve(MAX_PASSPHRASE_SIZE);
86     newpass1.reserve(MAX_PASSPHRASE_SIZE);
87     newpass2.reserve(MAX_PASSPHRASE_SIZE);
88     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
89     // Alternately, find a way to make this input mlock()'d to begin with.
90     oldpass.assign(ui->passEdit1->text().toStdString().c_str());
91     newpass1.assign(ui->passEdit2->text().toStdString().c_str());
92     newpass2.assign(ui->passEdit3->text().toStdString().c_str());
93
94     switch(mode)
95     {
96     case Encrypt: {
97         if(newpass1.empty() || newpass2.empty())
98         {
99             // Cannot encrypt with empty passphrase
100             break;
101         }
102         QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
103                  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?"),
104                  QMessageBox::Yes|QMessageBox::Cancel,
105                  QMessageBox::Cancel);
106         if(retval == QMessageBox::Yes)
107         {
108             if(newpass1 == newpass2)
109             {
110                 if(model->setWalletEncrypted(true, newpass1))
111                 {
112                     QMessageBox::warning(this, tr("Wallet encrypted"),
113                                          tr("Bitcoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."));
114                     QApplication::quit();
115                 }
116                 else
117                 {
118                     QMessageBox::critical(this, tr("Wallet encryption failed"),
119                                          tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
120                 }
121                 QDialog::accept(); // Success
122             }
123             else
124             {
125                 QMessageBox::critical(this, tr("Wallet encryption failed"),
126                                      tr("The supplied passphrases do not match."));
127             }
128         }
129         else
130         {
131             QDialog::reject(); // Cancelled
132         }
133         } break;
134     case Unlock:
135         if(!model->setWalletLocked(false, oldpass))
136         {
137             QMessageBox::critical(this, tr("Wallet unlock failed"),
138                                   tr("The passphrase entered for the wallet decryption was incorrect."));
139         }
140         else
141         {
142             QDialog::accept(); // Success
143         }
144         break;
145     case Decrypt:
146         if(!model->setWalletEncrypted(false, oldpass))
147         {
148             QMessageBox::critical(this, tr("Wallet decryption failed"),
149                                   tr("The passphrase entered for the wallet decryption was incorrect."));
150         }
151         else
152         {
153             QDialog::accept(); // Success
154         }
155         break;
156     case ChangePass:
157         if(newpass1 == newpass2)
158         {
159             if(model->changePassphrase(oldpass, newpass1))
160             {
161                 QMessageBox::information(this, tr("Wallet encrypted"),
162                                      tr("Wallet passphrase was succesfully changed."));
163                 QDialog::accept(); // Success
164             }
165             else
166             {
167                 QMessageBox::critical(this, tr("Wallet encryption failed"),
168                                      tr("The passphrase entered for the wallet decryption was incorrect."));
169             }
170         }
171         else
172         {
173             QMessageBox::critical(this, tr("Wallet encryption failed"),
174                                  tr("The supplied passphrases do not match."));
175         }
176         break;
177     }
178 }
179
180 void AskPassphraseDialog::textChanged()
181 {
182     // Validate input, set Ok button to enabled when accepable
183     bool acceptable = false;
184     switch(mode)
185     {
186     case Encrypt: // New passphrase x2
187         acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
188         break;
189     case Unlock: // Old passphrase x1
190     case Decrypt:
191         acceptable = !ui->passEdit1->text().isEmpty();
192         break;
193     case ChangePass: // Old passphrase x1, new passphrase x2
194         acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
195         break;
196     }
197     ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
198 }
199
200 bool AskPassphraseDialog::event(QEvent *event)
201 {
202     // Detect Caps Lock key press.
203     if (event->type() == QEvent::KeyPress) {
204         QKeyEvent *ke = static_cast<QKeyEvent *>(event);
205         if (ke->key() == Qt::Key_CapsLock) {
206             fCapsLock = !fCapsLock;
207         }
208         if (fCapsLock) {
209             ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
210         } else {
211             ui->capsLabel->clear();
212         }
213     }
214     return QWidget::event(event);
215 }
216
217 bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event)
218 {
219     /* Detect Caps Lock. 
220      * There is no good OS-independent way to check a key state in Qt, but we
221      * can detect Caps Lock by checking for the following condition:
222      * Shift key is down and the result is a lower case character, or
223      * Shift key is not down and the result is an upper case character.
224      */
225     if (event->type() == QEvent::KeyPress) {
226         QKeyEvent *ke = static_cast<QKeyEvent *>(event);
227         QString str = ke->text();
228         if (str.length() != 0) {
229             const QChar *psz = str.unicode();
230             bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
231             if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) {
232                 fCapsLock = true;
233                 ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
234             } else if (psz->isLetter()) {
235                 fCapsLock = false;
236                 ui->capsLabel->clear();
237             }
238         }
239     }
240     return false;
241 }