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 if (res != SigningResult::OK) { 159 ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); 160 ui->statusLabel_SM->setText(QString("<nobr>") + error + QString("</nobr>")); 161 return; 162 } 163 164 ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }"); 165 ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>")); 166 167 ui->signatureOut_SM->setText(QString::fromStdString(signature)); 168 } 169 170 void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked() 171 { 172 GUIUtil::setClipboard(ui->signatureOut_SM->text()); 173 } 174 175 void SignVerifyMessageDialog::on_clearButton_SM_clicked() 176 { 177 ui->addressIn_SM->clear(); 178 ui->messageIn_SM->clear(); 179 ui->signatureOut_SM->clear(); 180 ui->statusLabel_SM->clear(); 181 182 ui->addressIn_SM->setFocus(); 183 } 184 185 void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() 186 { 187 if (model && model->getAddressTableModel()) 188 { 189 AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); 190 dlg.setModel(model->getAddressTableModel()); 191 if (dlg.exec()) 192 { 193 setAddress_VM(dlg.getReturnValue()); 194 } 195 } 196 } 197 198 void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() 199 { 200 const std::string& address = ui->addressIn_VM->text().toStdString(); 201 const std::string& signature = ui->signatureIn_VM->text().toStdString(); 202 const std::string& message = ui->messageIn_VM->document()->toPlainText().toStdString(); 203 204 const auto result = MessageVerify(address, signature, message); 205 206 if (result == MessageVerificationResult::OK) { 207 ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }"); 208 } else { 209 ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); 210 } 211 212 switch (result) { 213 case MessageVerificationResult::OK: 214 ui->statusLabel_VM->setText( 215 QString("<nobr>") + tr("Message verified.") + QString("</nobr>") 216 ); 217 return; 218 case MessageVerificationResult::ERR_INVALID_ADDRESS: 219 ui->statusLabel_VM->setText( 220 tr("The entered address is invalid.") + QString(" ") + 221 tr("Please check the address and try again.") 222 ); 223 return; 224 case MessageVerificationResult::ERR_ADDRESS_NO_KEY: 225 ui->addressIn_VM->setValid(false); 226 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)); 227 return; 228 case MessageVerificationResult::ERR_MALFORMED_SIGNATURE: 229 ui->signatureIn_VM->setValid(false); 230 ui->statusLabel_VM->setText( 231 tr("The signature could not be decoded.") + QString(" ") + 232 tr("Please check the signature and try again.") 233 ); 234 return; 235 case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED: 236 ui->signatureIn_VM->setValid(false); 237 ui->statusLabel_VM->setText( 238 tr("The signature did not match the message digest.") + QString(" ") + 239 tr("Please check the signature and try again.") 240 ); 241 return; 242 case MessageVerificationResult::ERR_NOT_SIGNED: 243 ui->statusLabel_VM->setText( 244 QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>") 245 ); 246 return; 247 } 248 } 249 250 void SignVerifyMessageDialog::on_clearButton_VM_clicked() 251 { 252 ui->addressIn_VM->clear(); 253 ui->signatureIn_VM->clear(); 254 ui->messageIn_VM->clear(); 255 ui->statusLabel_VM->clear(); 256 257 ui->addressIn_VM->setFocus(); 258 } 259 260 bool SignVerifyMessageDialog::eventFilter(QObject *object, QEvent *event) 261 { 262 if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::FocusIn) 263 { 264 if (ui->tabWidget->currentIndex() == 0) 265 { 266 /* Clear status message on focus change */ 267 ui->statusLabel_SM->clear(); 268 269 /* Select generated signature */ 270 if (object == ui->signatureOut_SM) 271 { 272 ui->signatureOut_SM->selectAll(); 273 return true; 274 } 275 } 276 else if (ui->tabWidget->currentIndex() == 1) 277 { 278 /* Clear status message on focus change */ 279 ui->statusLabel_VM->clear(); 280 } 281 } 282 return QDialog::eventFilter(object, event); 283 } 284 285 void SignVerifyMessageDialog::changeEvent(QEvent* e) 286 { 287 if (e->type() == QEvent::PaletteChange) { 288 ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/address-book"))); 289 ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/editpaste"))); 290 ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/editcopy"))); 291 ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/edit"))); 292 ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove"))); 293 ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/address-book"))); 294 ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/transaction_0"))); 295 ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove"))); 296 } 297 298 QDialog::changeEvent(e); 299 }