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 }