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