/ src / qt / signverifymessagedialog.cpp
signverifymessagedialog.cpp
  1  // Copyright (c) 2011-2022 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  #include <qt/signverifymessagedialog.h>
  6  #include <qt/forms/ui_signverifymessagedialog.h>
  7  
  8  #include <qt/addressbookpage.h>
  9  #include <qt/guiutil.h>
 10  #include <qt/platformstyle.h>
 11  #include <qt/walletmodel.h>
 12  
 13  #include <key_io.h>
 14  #include <util/message.h> // For MessageSign(), MessageVerify()
 15  #include <wallet/wallet.h>
 16  
 17  #include <vector>
 18  
 19  #include <QClipboard>
 20  
 21  SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
 22      QDialog(parent, GUIUtil::dialog_flags),
 23      ui(new Ui::SignVerifyMessageDialog),
 24      platformStyle(_platformStyle)
 25  {
 26      ui->setupUi(this);
 27  
 28      ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
 29      ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
 30      ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
 31      ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
 32      ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
 33      ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
 34      ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/transaction_0"));
 35      ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
 36  
 37      GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
 38      GUIUtil::setupAddressWidget(ui->addressIn_VM, this);
 39  
 40      ui->addressIn_SM->installEventFilter(this);
 41      ui->messageIn_SM->installEventFilter(this);
 42      ui->signatureOut_SM->installEventFilter(this);
 43      ui->addressIn_VM->installEventFilter(this);
 44      ui->messageIn_VM->installEventFilter(this);
 45      ui->signatureIn_VM->installEventFilter(this);
 46  
 47      ui->signatureOut_SM->setFont(GUIUtil::fixedPitchFont());
 48      ui->signatureIn_VM->setFont(GUIUtil::fixedPitchFont());
 49  
 50      GUIUtil::handleCloseWindowShortcut(this);
 51  }
 52  
 53  SignVerifyMessageDialog::~SignVerifyMessageDialog()
 54  {
 55      delete ui;
 56  }
 57  
 58  void SignVerifyMessageDialog::setModel(WalletModel *_model)
 59  {
 60      this->model = _model;
 61  }
 62  
 63  void SignVerifyMessageDialog::setAddress_SM(const QString &address)
 64  {
 65      ui->addressIn_SM->setText(address);
 66      ui->messageIn_SM->setFocus();
 67  }
 68  
 69  void SignVerifyMessageDialog::setAddress_VM(const QString &address)
 70  {
 71      ui->addressIn_VM->setText(address);
 72      ui->messageIn_VM->setFocus();
 73  }
 74  
 75  void SignVerifyMessageDialog::showTab_SM(bool fShow)
 76  {
 77      ui->tabWidget->setCurrentIndex(0);
 78      if (fShow)
 79          this->show();
 80  }
 81  
 82  void SignVerifyMessageDialog::showTab_VM(bool fShow)
 83  {
 84      ui->tabWidget->setCurrentIndex(1);
 85      if (fShow)
 86          this->show();
 87  }
 88  
 89  void SignVerifyMessageDialog::on_addressBookButton_SM_clicked()
 90  {
 91      if (model && model->getAddressTableModel())
 92      {
 93          model->refresh(/*pk_hash_only=*/true);
 94          AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
 95          dlg.setModel(model->getAddressTableModel());
 96          if (dlg.exec())
 97          {
 98              setAddress_SM(dlg.getReturnValue());
 99          }
100      }
101  }
102  
103  void SignVerifyMessageDialog::on_pasteButton_SM_clicked()
104  {
105      setAddress_SM(QApplication::clipboard()->text());
106  }
107  
108  void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
109  {
110      if (!model)
111          return;
112  
113      /* Clear old signature to ensure users don't get confused on error with an old signature displayed */
114      ui->signatureOut_SM->clear();
115  
116      CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString());
117      if (!IsValidDestination(destination)) {
118          ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
119          ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
120          return;
121      }
122      const PKHash* pkhash = std::get_if<PKHash>(&destination);
123      if (!pkhash) {
124          ui->addressIn_SM->setValid(false);
125          ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
126          ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
127          return;
128      }
129  
130      WalletModel::UnlockContext ctx(model->requestUnlock());
131      if (!ctx.isValid())
132      {
133          ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
134          ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled."));
135          return;
136      }
137  
138      const std::string& message = ui->messageIn_SM->document()->toPlainText().toStdString();
139      std::string signature;
140      SigningResult res = model->wallet().signMessage(message, *pkhash, signature);
141  
142      QString error;
143      switch (res) {
144          case SigningResult::OK:
145              error = tr("No error");
146              break;
147          case SigningResult::PRIVATE_KEY_NOT_AVAILABLE:
148              error = tr("Private key for the entered address is not available.");
149              break;
150          case SigningResult::SIGNING_FAILED:
151              error = tr("Message signing failed.");
152              break;
153          // no default case, so the compiler can warn about missing cases
154      }
155  
156      if (res != SigningResult::OK) {
157          ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
158          ui->statusLabel_SM->setText(QString("<nobr>") + error + QString("</nobr>"));
159          return;
160      }
161  
162      ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
163      ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));
164  
165      ui->signatureOut_SM->setText(QString::fromStdString(signature));
166  }
167  
168  void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
169  {
170      GUIUtil::setClipboard(ui->signatureOut_SM->text());
171  }
172  
173  void SignVerifyMessageDialog::on_clearButton_SM_clicked()
174  {
175      ui->addressIn_SM->clear();
176      ui->messageIn_SM->clear();
177      ui->signatureOut_SM->clear();
178      ui->statusLabel_SM->clear();
179  
180      ui->addressIn_SM->setFocus();
181  }
182  
183  void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
184  {
185      if (model && model->getAddressTableModel())
186      {
187          AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
188          dlg.setModel(model->getAddressTableModel());
189          if (dlg.exec())
190          {
191              setAddress_VM(dlg.getReturnValue());
192          }
193      }
194  }
195  
196  void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
197  {
198      const std::string& address = ui->addressIn_VM->text().toStdString();
199      const std::string& signature = ui->signatureIn_VM->text().toStdString();
200      const std::string& message = ui->messageIn_VM->document()->toPlainText().toStdString();
201  
202      const auto result = MessageVerify(address, signature, message);
203  
204      if (result == MessageVerificationResult::OK) {
205          ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }");
206      } else {
207          ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
208      }
209  
210      switch (result) {
211      case MessageVerificationResult::OK:
212          ui->statusLabel_VM->setText(
213              QString("<nobr>") + tr("Message verified.") + QString("</nobr>")
214          );
215          return;
216      case MessageVerificationResult::ERR_INVALID_ADDRESS:
217          ui->statusLabel_VM->setText(
218              tr("The entered address is invalid.") + QString(" ") +
219              tr("Please check the address and try again.")
220          );
221          return;
222      case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
223          ui->addressIn_VM->setValid(false);
224          ui->statusLabel_VM->setText(
225              tr("The entered address does not refer to a key.") + QString(" ") +
226              tr("Please check the address and try again.")
227          );
228          return;
229      case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
230          ui->signatureIn_VM->setValid(false);
231          ui->statusLabel_VM->setText(
232              tr("The signature could not be decoded.") + QString(" ") +
233              tr("Please check the signature and try again.")
234          );
235          return;
236      case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
237          ui->signatureIn_VM->setValid(false);
238          ui->statusLabel_VM->setText(
239              tr("The signature did not match the message digest.") + QString(" ") +
240              tr("Please check the signature and try again.")
241          );
242          return;
243      case MessageVerificationResult::ERR_NOT_SIGNED:
244          ui->statusLabel_VM->setText(
245              QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")
246          );
247          return;
248      }
249  }
250  
251  void SignVerifyMessageDialog::on_clearButton_VM_clicked()
252  {
253      ui->addressIn_VM->clear();
254      ui->signatureIn_VM->clear();
255      ui->messageIn_VM->clear();
256      ui->statusLabel_VM->clear();
257  
258      ui->addressIn_VM->setFocus();
259  }
260  
261  bool SignVerifyMessageDialog::eventFilter(QObject *object, QEvent *event)
262  {
263      if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::FocusIn)
264      {
265          if (ui->tabWidget->currentIndex() == 0)
266          {
267              /* Clear status message on focus change */
268              ui->statusLabel_SM->clear();
269  
270              /* Select generated signature */
271              if (object == ui->signatureOut_SM)
272              {
273                  ui->signatureOut_SM->selectAll();
274                  return true;
275              }
276          }
277          else if (ui->tabWidget->currentIndex() == 1)
278          {
279              /* Clear status message on focus change */
280              ui->statusLabel_VM->clear();
281          }
282      }
283      return QDialog::eventFilter(object, event);
284  }
285  
286  void SignVerifyMessageDialog::changeEvent(QEvent* e)
287  {
288      if (e->type() == QEvent::PaletteChange) {
289          ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/address-book")));
290          ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/editpaste")));
291          ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/editcopy")));
292          ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/edit")));
293          ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove")));
294          ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/address-book")));
295          ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/transaction_0")));
296          ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove")));
297      }
298  
299      QDialog::changeEvent(e);
300  }