signverifymessagedialog.cpp
1 // Copyright (c) 2011-present 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 <common/signmessage.h> 14 #include <bitcoin-build-config.h> // IWYU pragma: keep 15 #include <key_io.h> 16 #include <wallet/wallet.h> 17 18 #include <string> 19 #include <variant> 20 #include <vector> 21 22 #include <QClipboard> 23 24 SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) : 25 QDialog(parent, GUIUtil::dialog_flags), 26 ui(new Ui::SignVerifyMessageDialog), 27 platformStyle(_platformStyle) 28 { 29 ui->setupUi(this); 30 31 ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book")); 32 ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste")); 33 ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy")); 34 ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/edit")); 35 ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); 36 ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book")); 37 ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/transaction_0")); 38 ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); 39 40 GUIUtil::setupAddressWidget(ui->addressIn_SM, this); 41 GUIUtil::setupAddressWidget(ui->addressIn_VM, this); 42 43 ui->addressIn_SM->installEventFilter(this); 44 ui->messageIn_SM->installEventFilter(this); 45 ui->signatureOut_SM->installEventFilter(this); 46 ui->addressIn_VM->installEventFilter(this); 47 ui->messageIn_VM->installEventFilter(this); 48 ui->signatureIn_VM->installEventFilter(this); 49 50 ui->signatureOut_SM->setFont(GUIUtil::fixedPitchFont()); 51 ui->signatureIn_VM->setFont(GUIUtil::fixedPitchFont()); 52 53 GUIUtil::handleCloseWindowShortcut(this); 54 } 55 56 SignVerifyMessageDialog::~SignVerifyMessageDialog() 57 { 58 delete ui; 59 } 60 61 void SignVerifyMessageDialog::setModel(WalletModel *_model) 62 { 63 this->model = _model; 64 } 65 66 void SignVerifyMessageDialog::setAddress_SM(const QString &address) 67 { 68 ui->addressIn_SM->setText(address); 69 ui->messageIn_SM->setFocus(); 70 } 71 72 void SignVerifyMessageDialog::setAddress_VM(const QString &address) 73 { 74 ui->addressIn_VM->setText(address); 75 ui->messageIn_VM->setFocus(); 76 } 77 78 void SignVerifyMessageDialog::showTab_SM(bool fShow) 79 { 80 ui->tabWidget->setCurrentIndex(0); 81 if (fShow) 82 this->show(); 83 } 84 85 void SignVerifyMessageDialog::showTab_VM(bool fShow) 86 { 87 ui->tabWidget->setCurrentIndex(1); 88 if (fShow) 89 this->show(); 90 } 91 92 void SignVerifyMessageDialog::on_addressBookButton_SM_clicked() 93 { 94 if (model && model->getAddressTableModel()) 95 { 96 model->refresh(/*pk_hash_only=*/true); 97 AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); 98 dlg.setModel(model->getAddressTableModel()); 99 if (dlg.exec()) 100 { 101 setAddress_SM(dlg.getReturnValue()); 102 } 103 } 104 } 105 106 void SignVerifyMessageDialog::on_pasteButton_SM_clicked() 107 { 108 setAddress_SM(QApplication::clipboard()->text()); 109 } 110 111 void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() 112 { 113 if (!model) 114 return; 115 116 /* Clear old signature to ensure users don't get confused on error with an old signature displayed */ 117 ui->signatureOut_SM->clear(); 118 119 CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString()); 120 if (!IsValidDestination(destination)) { 121 ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); 122 ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); 123 return; 124 } 125 const PKHash* pkhash = std::get_if<PKHash>(&destination); 126 if (!pkhash) { 127 ui->addressIn_SM->setValid(false); 128 ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); 129 ui->statusLabel_SM->setText(tr("The entered address does not refer to a legacy (P2PKH) key. Message signing for SegWit and other non-P2PKH address types is not supported in this version of %1. Please check the address and try again.").arg(CLIENT_NAME)); 130 return; 131 } 132 133 WalletModel::UnlockContext ctx(model->requestUnlock()); 134 if (!ctx.isValid()) 135 { 136 ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); 137 ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled.")); 138 return; 139 } 140 141 const std::string& message = ui->messageIn_SM->document()->toPlainText().toStdString(); 142 std::string signature; 143 SigningResult res = model->wallet().signMessage(message, *pkhash, signature); 144 145 QString error; 146 switch (res) { 147 case SigningResult::OK: 148 error = tr("No error"); 149 break; 150 case SigningResult::PRIVATE_KEY_NOT_AVAILABLE: 151 error = tr("Private key for the entered address is not available."); 152 break; 153 case SigningResult::SIGNING_FAILED: 154 error = tr("Message signing failed."); 155 break; 156 // no default case, so the compiler can warn about missing cases 157 } 158 159 if (res != SigningResult::OK) { 160 ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); 161 ui->statusLabel_SM->setText(QString("<nobr>") + error + QString("</nobr>")); 162 return; 163 } 164 165 ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }"); 166 ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>")); 167 168 ui->signatureOut_SM->setText(QString::fromStdString(signature)); 169 } 170 171 void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked() 172 { 173 GUIUtil::setClipboard(ui->signatureOut_SM->text()); 174 } 175 176 void SignVerifyMessageDialog::on_clearButton_SM_clicked() 177 { 178 ui->addressIn_SM->clear(); 179 ui->messageIn_SM->clear(); 180 ui->signatureOut_SM->clear(); 181 ui->statusLabel_SM->clear(); 182 183 ui->addressIn_SM->setFocus(); 184 } 185 186 void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() 187 { 188 if (model && model->getAddressTableModel()) 189 { 190 AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); 191 dlg.setModel(model->getAddressTableModel()); 192 if (dlg.exec()) 193 { 194 setAddress_VM(dlg.getReturnValue()); 195 } 196 } 197 } 198 199 void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() 200 { 201 const std::string& address = ui->addressIn_VM->text().toStdString(); 202 const std::string& signature = ui->signatureIn_VM->text().toStdString(); 203 const std::string& message = ui->messageIn_VM->document()->toPlainText().toStdString(); 204 205 const auto result = MessageVerify(address, signature, message); 206 207 if (result == MessageVerificationResult::OK) { 208 ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }"); 209 } else { 210 ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); 211 } 212 213 switch (result) { 214 case MessageVerificationResult::OK: 215 ui->statusLabel_VM->setText( 216 QString("<nobr>") + tr("Message verified.") + QString("</nobr>") 217 ); 218 return; 219 case MessageVerificationResult::ERR_INVALID_ADDRESS: 220 ui->statusLabel_VM->setText( 221 tr("The entered address is invalid.") + QString(" ") + 222 tr("Please check the address and try again.") 223 ); 224 return; 225 case MessageVerificationResult::ERR_ADDRESS_NO_KEY: 226 ui->addressIn_VM->setValid(false); 227 ui->statusLabel_VM->setText(tr("The entered address does not refer to a legacy (P2PKH) key. Message signing for SegWit and other non-P2PKH address types is not supported in this version of %1. Please check the address and try again.").arg(CLIENT_NAME)); 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 }