Move signature verification functions to CPubKey.
[novacoin.git] / src / qt / signverifymessagedialog.cpp
1 #include "signverifymessagedialog.h"
2 #include "ui_signverifymessagedialog.h"
3
4 #include "addressbookpage.h"
5 #include "base58.h"
6 #include "guiutil.h"
7 #include "dialogwindowflags.h"
8 #include "init.h"
9 #include "main.h"
10 #include "optionsmodel.h"
11 #include "walletmodel.h"
12 #include "wallet.h"
13
14 #include <string>
15 #include <vector>
16
17 #include <QClipboard>
18 #include <QKeyEvent>
19
20 SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
21     QWidget(parent, DIALOGWINDOWHINTS),
22     ui(new Ui::SignVerifyMessageDialog),
23     model(0)
24 {
25     ui->setupUi(this);
26
27 #if (QT_VERSION >= 0x040700)
28     /* Do not move this to the XML file, Qt before 4.7 will choke on it */
29     ui->addressIn_SM->setPlaceholderText(tr("Enter a NovaCoin address (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)"));
30     ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));
31
32     ui->addressIn_VM->setPlaceholderText(tr("Enter a NovaCoin address (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)"));
33     ui->signatureIn_VM->setPlaceholderText(tr("Enter NovaCoin signature"));
34 #endif
35
36     GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
37     GUIUtil::setupAddressWidget(ui->addressIn_VM, this);
38
39     ui->addressIn_SM->installEventFilter(this);
40     ui->messageIn_SM->installEventFilter(this);
41     ui->signatureOut_SM->installEventFilter(this);
42     ui->addressIn_VM->installEventFilter(this);
43     ui->messageIn_VM->installEventFilter(this);
44     ui->signatureIn_VM->installEventFilter(this);
45
46     ui->signatureOut_SM->setFont(GUIUtil::bitcoinAddressFont());
47     ui->signatureIn_VM->setFont(GUIUtil::bitcoinAddressFont());
48 }
49
50 SignVerifyMessageDialog::~SignVerifyMessageDialog()
51 {
52     delete ui;
53 }
54
55 void SignVerifyMessageDialog::setModel(WalletModel *model)
56 {
57     this->model = model;
58 }
59
60 void SignVerifyMessageDialog::setAddress_SM(QString address)
61 {
62     ui->addressIn_SM->setText(address);
63     ui->messageIn_SM->setFocus();
64 }
65
66 void SignVerifyMessageDialog::setAddress_VM(QString address)
67 {
68     ui->addressIn_VM->setText(address);
69     ui->messageIn_VM->setFocus();
70 }
71
72 void SignVerifyMessageDialog::showTab_SM(bool fShow)
73 {
74     ui->tabWidget->setCurrentIndex(0);
75
76     if (fShow)
77         this->show();
78 }
79
80 void SignVerifyMessageDialog::showTab_VM(bool fShow)
81 {
82     ui->tabWidget->setCurrentIndex(1);
83     if (fShow)
84         this->show();
85 }
86
87 void SignVerifyMessageDialog::on_addressBookButton_SM_clicked()
88 {
89     if (model && model->getAddressTableModel())
90     {
91         AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::ReceivingTab, this);
92         dlg.setModel(model->getAddressTableModel());
93         if (dlg.exec())
94         {
95             setAddress_SM(dlg.getReturnValue());
96         }
97     }
98 }
99
100 void SignVerifyMessageDialog::on_pasteButton_SM_clicked()
101 {
102     setAddress_SM(QApplication::clipboard()->text());
103 }
104
105 void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
106 {
107     /* Clear old signature to ensure users don't get confused on error with an old signature displayed */
108     ui->signatureOut_SM->clear();
109
110     CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
111     if (!addr.IsValid())
112     {
113         ui->addressIn_SM->setValid(false);
114         ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
115         ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
116         return;
117     }
118     CKeyID keyID;
119     if (!addr.GetKeyID(keyID))
120     {
121         ui->addressIn_SM->setValid(false);
122         ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
123         ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
124         return;
125     }
126
127     WalletModel::UnlockContext ctx(model->requestUnlock());
128     if (!ctx.isValid())
129     {
130         ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
131         ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled."));
132         return;
133     }
134
135     CKey key;
136     if (!pwalletMain->GetKey(keyID, key))
137     {
138         ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
139         ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
140         return;
141     }
142
143     CDataStream ss(SER_GETHASH, 0);
144     ss << strMessageMagic;
145     ss << ui->messageIn_SM->document()->toPlainText().toStdString();
146
147     std::vector<unsigned char> vchSig;
148     if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
149     {
150         ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
151         ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>"));
152         return;
153     }
154
155     ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
156     ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));
157
158     ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size())));
159 }
160
161 void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
162 {
163     QApplication::clipboard()->setText(ui->signatureOut_SM->text());
164 }
165
166 void SignVerifyMessageDialog::on_clearButton_SM_clicked()
167 {
168     ui->addressIn_SM->clear();
169     ui->messageIn_SM->clear();
170     ui->signatureOut_SM->clear();
171     ui->statusLabel_SM->clear();
172
173     ui->addressIn_SM->setFocus();
174 }
175
176 void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
177 {
178     if (model && model->getAddressTableModel())
179     {
180         AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this);
181         dlg.setModel(model->getAddressTableModel());
182         if (dlg.exec())
183         {
184             setAddress_VM(dlg.getReturnValue());
185         }
186     }
187 }
188
189 void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
190 {
191     CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
192     if (!addr.IsValid())
193     {
194         ui->addressIn_VM->setValid(false);
195         ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
196         ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
197         return;
198     }
199     CKeyID keyID;
200     if (!addr.GetKeyID(keyID))
201     {
202         ui->addressIn_VM->setValid(false);
203         ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
204         ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
205         return;
206     }
207
208     bool fInvalid = false;
209     std::vector<unsigned char> vchSig = DecodeBase64(ui->signatureIn_VM->text().toStdString().c_str(), &fInvalid);
210
211     if (fInvalid)
212     {
213         ui->signatureIn_VM->setValid(false);
214         ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
215         ui->statusLabel_VM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again."));
216         return;
217     }
218
219     CDataStream ss(SER_GETHASH, 0);
220     ss << strMessageMagic;
221     ss << ui->messageIn_VM->document()->toPlainText().toStdString();
222
223     CPubKey key;
224     if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
225     {
226         ui->signatureIn_VM->setValid(false);
227         ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
228         ui->statusLabel_VM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again."));
229         return;
230     }
231
232     if (!(CBitcoinAddress(key.GetID()) == addr))
233     {
234         ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
235         ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
236         return;
237     }
238
239     ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }");
240     ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verified.") + QString("</nobr>"));
241 }
242
243 void SignVerifyMessageDialog::on_clearButton_VM_clicked()
244 {
245     ui->addressIn_VM->clear();
246     ui->signatureIn_VM->clear();
247     ui->messageIn_VM->clear();
248     ui->statusLabel_VM->clear();
249
250     ui->addressIn_VM->setFocus();
251 }
252
253 bool SignVerifyMessageDialog::eventFilter(QObject *object, QEvent *event)
254 {
255     if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::FocusIn)
256     {
257         if (ui->tabWidget->currentIndex() == 0)
258         {
259             /* Clear status message on focus change */
260             ui->statusLabel_SM->clear();
261
262             /* Select generated signature */
263             if (object == ui->signatureOut_SM)
264             {
265                 ui->signatureOut_SM->selectAll();
266                 return true;
267             }
268         }
269         else if (ui->tabWidget->currentIndex() == 1)
270         {
271             /* Clear status message on focus change */
272             ui->statusLabel_VM->clear();
273         }
274     }
275     return QWidget::eventFilter(object, event);
276 }
277
278 void SignVerifyMessageDialog::keyPressEvent(QKeyEvent *event)
279 {
280 #ifdef ANDROID
281     if(event->key() == Qt::Key_Back)
282     {
283         close();
284     }
285 #else
286     if(event->key() == Qt::Key_Escape)
287     {
288         close();
289     }
290 #endif
291 }